package com.xbongbong.coolapp.service.impl;

import com.alibaba.dingtalk.openapi.exception.OApiException;
import com.alibaba.dingtalk.openapi.helper.AuthHelper;
import com.alibaba.dingtalk.openapi.helper.DingCoolAppHelper;
import com.alibaba.dingtalk.openapi.helper.Env;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.coolapp.BizManager;
import com.xbongbong.coolapp.service.CoolAppCardService;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasCommentEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasCommentEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasProcessNodeTaskEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.NodeTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.enums.TaskTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.PaasFormHelp;
import com.xbongbong.paas.help.menu.InitMenuHelp;
import com.xbongbong.paas.model.PaasCommentModel;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.PaasProcessNodeTaskModel;
import com.xbongbong.paas.pojo.ItemDataPoJo;
import com.xbongbong.paas.pojo.SummaryDataPoJo;
import com.xbongbong.paas.pojo.dto.FormDataGetDTO;
import com.xbongbong.paas.pojo.dto.ParseSingleRowDataDTO;
import com.xbongbong.paas.pojo.dto.UserAndDepartmentGetDTO;
import com.xbongbong.paas.pojo.vo.FormDataGetVO;
import com.xbongbong.paas.pojo.vo.ParseSingleRowDataVO;
import com.xbongbong.paas.service.DetailStageService;
import com.xbongbong.paas.service.PaasFormDataService;
import com.xbongbong.paas.service.WorkReportSetService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.thread.TransmittableThreadLocalUtil;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.util.URLEncodeUtils;
import com.xbongbong.paas.toolbox.wrap.BaseVO;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.paas.util.ItemUtil;
import com.xbongbong.parent.parse.data.FormDataGetAnalysisDataHelp;
import com.xbongbong.pro.businesstage.pojo.StageGetAllListPojo;
import com.xbongbong.pro.businesstage.pojo.StageGetOneListPojo;
import com.xbongbong.pro.businesstage.pojo.dto.StageDetailDTO;
import com.xbongbong.pro.businesstage.pojo.dto.StageGetDTO;
import com.xbongbong.pro.businesstage.pojo.vo.StageDetailVO;
import com.xbongbong.pro.businesstage.pojo.vo.StageGetVO;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.coolapp.pojo.CardDataPojo;
import com.xbongbong.pro.coolapp.pojo.CardDataProcessNode;
import com.xbongbong.pro.coolapp.pojo.CardDataProcessUpdatePojo;
import com.xbongbong.pro.coolapp.pojo.CardDataSummaryPojo;
import com.xbongbong.pro.coolapp.pojo.CardProcessWorkflowPojo;
import com.xbongbong.pro.coolapp.pojo.CardPropertyPojo;
import com.xbongbong.pro.coolapp.pojo.CardTemplateExplainPojo;
import com.xbongbong.pro.coolapp.pojo.dto.CoolAppCloseCardDTO;
import com.xbongbong.pro.coolapp.pojo.dto.CoolAppSendCardDTO;
import com.xbongbong.pro.coolapp.pojo.dto.CoolAppSendRemindTopCardDTO;
import com.xbongbong.pro.coolapp.pojo.dto.CoolAppUpdateCardDTO;
import com.xbongbong.pro.coolapp.pojo.dto.CoolAppWorkReportTopCardDTO;
import com.xbongbong.pro.coolapp.pojo.dto.CoolAppWorkflowCardDTO;
import com.xbongbong.pro.domain.entity.AppModuleEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.coolapp.enums.CardTypeEnum;
import com.xbongbong.pro.enums.coolapp.enums.CardUseSceneEnum;
import com.xbongbong.pro.enums.coolapp.enums.TopCardTypeEnum;
import com.xbongbong.pro.enums.errorcodes.CoolAppErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.WorkReportErrorCodeEnum;
import com.xbongbong.pro.enums.menu.enums.CoolAppButtonOperateEnum;
import com.xbongbong.pro.enums.menu.enums.SystemAppMenuEnum;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.menu.pojo.dto.MenuInitDTO;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.service.cool.app.CoolAppProcessCardService;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.CoolAppConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.CommunicatePlanUserEntity;
import com.xbongbong.saas.domain.entity.CoolAppCardDataEntity;
import com.xbongbong.saas.domain.entity.CoolAppCardTemplateEntity;
import com.xbongbong.saas.domain.entity.DingBundleEntity;
import com.xbongbong.saas.domain.entity.LikeEntity;
import com.xbongbong.saas.domain.entity.UserTeamEntity;
import com.xbongbong.saas.domain.entity.ext.CommunicatePlanEntityExt;
import com.xbongbong.saas.domain.entity.ext.CustomerCommunicateEntityExt;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.enums.BusinessCommentEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.CommunicatePlanEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerCommunicateEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.enums.business.WorkReportDailyEnum;
import com.xbongbong.saas.enums.business.WorkReportFieldEnum;
import com.xbongbong.saas.enums.business.WorkReportTypeEnum;
import com.xbongbong.saas.enums.mini.DingBundleStatusEnum;
import com.xbongbong.saas.enums.mini.DingBundleTypeEnum;
import com.xbongbong.saas.help.SaasGetHelp;
import com.xbongbong.saas.model.AppModuleModel;
import com.xbongbong.saas.model.CommunicatePlanModel;
import com.xbongbong.saas.model.CommunicatePlanUserModel;
import com.xbongbong.saas.model.CoolAppCardDataModel;
import com.xbongbong.saas.model.CoolAppCardTemplateModel;
import com.xbongbong.saas.model.CustomerCommunicateModel;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.DingBundleModel;
import com.xbongbong.saas.model.LikeModel;
import com.xbongbong.saas.service.LikeService;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.UserModel;
import com.xbongbong.util.CoolAppCardUtil;
import com.xbongbong.workflow.domain.entity.WorkflowTaskNodeEntity;
import com.xbongbong.workflow.model.WorkflowTaskNodeModel;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;


/**
 * @author zhushuainan
 * @title: CoolAppCardServiceImpl
 * @projectName xbb-pro
 * @description: 酷应用卡片Service
 * @date 2022/6/13 14:52
 */
@Service("coolAppCardServiceImpl")
public class CoolAppCardServiceImpl implements CoolAppCardService {
    private static  final Logger LOG = LoggerFactory.getLogger(CoolAppCardServiceImpl.class);

    private static final String COMPLEX_PARAM = "sys_full_json_obj";

    @Resource
    private CoolAppCardDataModel coolAppCardDataModel;
    @Resource
    private CoolAppCardTemplateModel coolAppCardTemplateModel;
    @Resource
    private ProBaseConfig proBaseConfig;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private UserModel userModel;
    @Resource
    private CustomerCommunicateModel customerCommunicateModel;
    @Resource
    private DingCoolAppHelper dingCoolAppHelper;
    @Resource
    private AuthHelper authHelper;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private SaasGetHelp saasGetHelp;
    @Resource
    private PaasFormHelp paasFormHelp;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private PaasCommentModel paasCommentModel;
    @Resource
    private LikeService likeService;
    @Resource
    private DingBundleModel dingBundleModel;
    @Resource
    private BizManager bizManager;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private DetailStageService detailStageService;
    @Resource
    private PaasFormDataService paasFormDataService;
    @Resource
    private PaasProcessNodeTaskModel paasProcessNodeTaskModel;
    @Resource
    private WorkflowTaskNodeModel workflowTaskNodeModel;
    @Resource
    private LikeModel likeModel;
    @Resource
    private CoolAppProcessCardService coolAppProcessCardService;
    @Resource
    private FormDataGetAnalysisDataHelp formDataGetAnalysisDataHelp;
    @Resource
    private AppModuleModel appModuleModel;
    @Resource
    private InitMenuHelp initMenuHelp;
    @Resource
    private CommunicatePlanUserModel communicatePlanUserModel;
    @Resource
    private CommunicatePlanModel communicatePlanModel;
    @Resource
    private PushHelper pushHelper;
    @Resource
    private WorkReportSetService workReportSetService;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;

    @Override
    public BaseVO sendCard(CoolAppSendCardDTO coolAppSendCardDTO) throws XbbException {
        BaseVO baseVO = new BaseVO();
        String corpid = coolAppSendCardDTO.getCorpid();
        Integer businessType = coolAppSendCardDTO.getBusinessType();
        Long dataId = coolAppSendCardDTO.getDataId();
        Long formId = coolAppSendCardDTO.getFormId();
        String openConversationId = coolAppSendCardDTO.getOpenConversationId();
        openConversationId = CoolAppCardUtil.decodeOpenConversationId(openConversationId);
        coolAppSendCardDTO.setOpenConversationId(openConversationId);
        // 群id不能为空
        if (StringUtil.isEmpty(openConversationId)) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520001);
        }
        // 酷应用：不能为空或卸载
        DingBundleEntity dingBundleEntity = dingBundleModel.getByType(corpid, openConversationId, DingBundleTypeEnum.COOL_APP.getCode());
        if (Objects.isNull(dingBundleEntity) || Objects.equals(dingBundleEntity.getStatus(), DingBundleStatusEnum.DISMISS.getCode())) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520002);
        }
        // 只有客户、合同、跟进记录、跟进记录评论回复
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        boolean noNeedCardFlag = !(xbbRefTypeEnum == XbbRefTypeEnum.CUSTOMER_MANAGEMENT || xbbRefTypeEnum == XbbRefTypeEnum.CONTRACT || xbbRefTypeEnum == XbbRefTypeEnum.CUSTOMER_COMMUNICATE
                || xbbRefTypeEnum == XbbRefTypeEnum.SALES_OPPORTUNITY || xbbRefTypeEnum == XbbRefTypeEnum.COMMUNICATE_PLAN || xbbRefTypeEnum == XbbRefTypeEnum.WORK_REPORT);
        if (noNeedCardFlag) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520003);
        }
        // 使用场景
        CardUseSceneEnum cardUseSceneEnum = CardUseSceneEnum.getByType(coolAppSendCardDTO.getUseScene());
        if (Objects.isNull(cardUseSceneEnum)) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520004);
        }
        // 卡片类型：互动 || 吊顶(审批工作流、跟进提醒)
        Integer cardType = (cardUseSceneEnum == CardUseSceneEnum.REMIND || cardUseSceneEnum == CardUseSceneEnum.PROCESS_OR_WORKFLOW) ? CardTypeEnum.TOP_CARD.getType() : CardTypeEnum.IM_CARD.getType();

        CoolAppCardTemplateEntity coolAppCardTemplateEntity = coolAppCardTemplateModel.getByUseScene(cardType, cardUseSceneEnum.getType());
        if(Objects.isNull(coolAppCardTemplateEntity)){
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520004);
        }
        String cardId = coolAppCardTemplateEntity.getCardId();
        // 获取接收人列表
        Set<String> userIds = new HashSet<>();
        String creatorId = "";
        PaasFormDataEntityExt paasFormDataEntityExt = null;
        PaasCommentEntity paasCommentEntity = null;
        // 获取实体
        switch (cardUseSceneEnum) {
            case BUSINESS:
                // 获取数据
                paasFormDataEntityExt = saasGetHelp.getFormData(dataId, corpid, coolAppSendCardDTO.getBusinessType());
                if (Objects.isNull(paasFormDataEntityExt)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
                }
                if (Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode())) {
                    JSONObject data = paasFormDataEntityExt.getData();
                    // 获取客户相关数据
                    Long customerId = FastJsonHelper.getLongFromFormData(data, CustomerCommunicateEnum.CUSTOMER_NAME.getAttr());
                    CustomerEntityExt customerEntityExt = customerModel.getByKey(customerId, corpid);
                    Long customerFormId = Objects.isNull(customerEntityExt) ? null : customerEntityExt.getFormId();
                    getCustomerCommunicateTeamMember(corpid, customerFormId, customerId , userIds, paasFormDataEntityExt.getCreatorId());
                } else if (Objects.equals(businessType, XbbRefTypeEnum.COMMUNICATE_PLAN.getCode())){
                    Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    param.put(StringConstant.CORPID,corpid);
                    param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
                    param.put("dataId",dataId);
                    List<CommunicatePlanUserEntity> planUserEntities = communicatePlanUserModel.findEntitys(param);
                    if (CollectionsUtil.isNotEmpty(planUserEntities)){
                        planUserEntities.forEach(item -> userIds.add(item.getUserId()));
                    }
                } else if (Objects.equals(businessType, XbbRefTypeEnum.WORK_REPORT.getCode())){
                    formId = paasFormDataEntityExt.getFormId();
                    coolAppSendCardDTO.setFormId(formId);
                    List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.WORK_REPORT_ADD_PUSH.getCode(), PushTypeEnum.WORK_REPORT_ADD_PUSH.getSubCode(), coolAppSendCardDTO.getLoginUser(), paasFormDataEntityExt);
                    userIds.addAll(pushUserList);
                    userIds.add(coolAppSendCardDTO.getUserId());
                } else {
                    getBusinessTeamMember(corpid, dataId, businessType , userIds);
                }
                creatorId = paasFormDataEntityExt.getCreatorId();
                break;
            case STAGE:
                // 客户团队负责人、协同人 & 阶段字段可见权限
                // dataId为客户数据id，formId为客户表单id
                List<UserTeamEntity> userTeamEntities = userTeamHelp.getUserTeamList(Arrays.asList(dataId), corpid, businessType, Boolean.FALSE, null);
                PaasFormExplainEntity formExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
                String explains = formExplainEntity.getExplains();
                Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explains);
                // 添加接收人
                addStageReceiverList(explainMap,userIds,corpid,creatorId, userTeamEntities);
                break;
            case COMMUNICATE_REPLY:
                // 评论的内容创建人、评论的被回复人
                // dataId为评论数据id
                paasCommentEntity = paasCommentModel.getByKey(dataId, corpid);
                if (Objects.isNull(paasCommentEntity)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
                }
                userIds.add(paasCommentEntity.getUserId());
                if (!Objects.equals(paasCommentEntity.getUserId(),paasCommentEntity.getRefUserId())){
                    userIds.add(paasCommentEntity.getRefUserId());
                }
                paasFormDataEntityExt = customerCommunicateModel.getByKey(paasCommentEntity.getRefId(), corpid);
                if (Objects.isNull(paasFormDataEntityExt)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
                }
                break;
            default:
                break;
        }

        // 卡片接收人无，不发送卡片
        if (CollectionsUtil.isEmpty(userIds)) {
            LOG.error("卡片接收人为空");
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520005);
        }
        //保存卡片数据
        CoolAppCardDataEntity cardDataEntity;
        cardDataEntity = saveCardData(coolAppSendCardDTO, cardId,JSONArray.parseArray(JSON.toJSONString(userIds)), creatorId, null, null, null);
        if (Objects.equals(coolAppSendCardDTO.getBusinessType(), XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode())) {
            JSONObject data = paasFormDataEntityExt.getData();
            Integer isRemind = data.getInteger(CustomerCommunicateEnum.IF_REMIND.getAttr());
            if (Objects.equals(BasicConstant.ONE, isRemind)){
                Long customerId = data.getLong(CustomerCommunicateEnum.CUSTOMER_NAME.getAttr());
                CoolAppCardTemplateEntity cardTemplateEntity = coolAppCardTemplateModel.getByUseScene(CardTypeEnum.TOP_CARD.getType(), CardUseSceneEnum.TOP_CARD.getType());
                // 保存跟进提醒吊顶卡片数据
                List<String> receverIds = new ArrayList<>();
                receverIds.add(paasFormDataEntityExt.getCreatorId());
                saveCardData(coolAppSendCardDTO, cardTemplateEntity.getCardId(),JSONArray.parseArray(JSON.toJSONString(receverIds)), creatorId, null, customerId, null);
            }
        }
        if (Objects.equals(coolAppSendCardDTO.getBusinessType(), XbbRefTypeEnum.COMMUNICATE_PLAN.getCode())){
            JSONObject data = paasFormDataEntityExt.getData();
            String type = data.getString(CommunicatePlanEnum.NOTIFY_TYPE.getAttr());
            // 访客计划开启了提醒
            if (!Objects.equals(type,"0")){
                CoolAppCardTemplateEntity cardTemplateEntity = coolAppCardTemplateModel.getByUseScene(CardTypeEnum.TOP_CARD.getType(), CardUseSceneEnum.TOP_CARD.getType());
                saveCardData(coolAppSendCardDTO, cardTemplateEntity.getCardId(),JSONArray.parseArray(JSON.toJSONString(userIds)), creatorId, null, dataId, null);
            }
        }
        if (CollectionsUtil.isNotEmpty(userIds)) {
            send(corpid, paasFormDataEntityExt, cardDataEntity, coolAppCardTemplateEntity, cardUseSceneEnum, coolAppSendCardDTO, paasCommentEntity);
        }
        return baseVO;
    }

    @Override
    public BaseVO sendWorkReportTopCard(CoolAppWorkReportTopCardDTO coolAppWorkReportTopCardDTO) throws XbbException {
        BaseVO baseVO = new BaseVO();
        String corpid = coolAppWorkReportTopCardDTO.getCorpid();
        String userId = coolAppWorkReportTopCardDTO.getUserId();
        Integer businessType = coolAppWorkReportTopCardDTO.getBusinessType();
        String openConversationId = coolAppWorkReportTopCardDTO.getOpenConversationId();
        openConversationId = CoolAppCardUtil.decodeOpenConversationId(openConversationId);
        coolAppWorkReportTopCardDTO.setOpenConversationId(openConversationId);
        // 群id不能为空
        if (StringUtil.isEmpty(openConversationId)) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520001);
        }

        // 酷应用：不能为空或卸载
        DingBundleEntity dingBundleEntity = dingBundleModel.getByType(corpid, openConversationId, DingBundleTypeEnum.COOL_APP.getCode());
        if (Objects.isNull(dingBundleEntity) || Objects.equals(dingBundleEntity.getStatus(), DingBundleStatusEnum.DISMISS.getCode())) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520002);
        }

        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        boolean noNeedCardFlag = !(xbbRefTypeEnum == XbbRefTypeEnum.CUSTOMER_MANAGEMENT || xbbRefTypeEnum == XbbRefTypeEnum.CONTRACT || xbbRefTypeEnum == XbbRefTypeEnum.CUSTOMER_COMMUNICATE
                || xbbRefTypeEnum == XbbRefTypeEnum.SALES_OPPORTUNITY || xbbRefTypeEnum == XbbRefTypeEnum.COMMUNICATE_PLAN || xbbRefTypeEnum == XbbRefTypeEnum.WORK_REPORT);
        if (noNeedCardFlag) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520003);
        }
        CoolAppCardTemplateEntity coolAppCardTemplateEntity = coolAppCardTemplateModel.getByUseScene(CardTypeEnum.TOP_CARD.getType(), CardUseSceneEnum.TOP_CARD.getType());
        if(Objects.isNull(coolAppCardTemplateEntity)){
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520004);
        }
        String cardId = coolAppCardTemplateEntity.getCardId();

        List<String> userIdList = getNotHandReportUserIdList(coolAppWorkReportTopCardDTO);

        String accessToken;
        try {
            accessToken = authHelper.getAccessToken(corpid);
        } catch (OApiException e) {
            accessToken = null;
        }
        // 获取群成员
        List<String> groupMembers = dingCoolAppHelper.getGroupMembers(accessToken, openConversationId, proBaseConfig.getCoolAppCode());
        //取交集
        userIdList.retainAll(groupMembers);

        // 卡片接收人无，不发送卡片
        if (CollectionsUtil.isEmpty(userIdList)) {
            LOG.error("卡片接收人为空");
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520005);
        }

        CoolAppCardDataEntity coolAppCardDataEntity = saveTopCardData(coolAppWorkReportTopCardDTO, cardId, JSONArray.parseArray(JSON.toJSONString(userIdList)), userId, null, null, null);

        try {
            sendWorkReportTopCard(coolAppWorkReportTopCardDTO,coolAppCardTemplateEntity, coolAppCardDataEntity, accessToken);
        } catch (Exception e) {
            LOG.error("send Top Card failed", e);
        }

        return baseVO;
    }

    public void sendWorkReportTopCard(CoolAppWorkReportTopCardDTO coolAppWorkReportTopCardDTO, CoolAppCardTemplateEntity coolAppCardTemplateEntity, CoolAppCardDataEntity cardDataEntity, String accessToken){

        JSONObject explain = coolAppCardTemplateEntity.getExplain();
        CardTemplateExplainPojo cardTemplateExplainPojo = explain.toJavaObject(CardTemplateExplainPojo.class);
        JSONArray receiverUserIds = cardDataEntity.getReceiverUserIds();

        // 标题
        String title = "未收到您的工作报告，请及时处理";
        JSONArray jsonArray = new JSONArray();
        List<String> reportDate = coolAppWorkReportTopCardDTO.getReportDate();
        String date = reportDate.get(0);
        Integer reportType = coolAppWorkReportTopCardDTO.getReportType();
        WorkReportTypeEnum workReportTypeEnum = WorkReportTypeEnum.getByType(reportType);
        String typeName = workReportTypeEnum.getName();

        jsonArray.add(new ItemDataPoJo(I18nMessageUtil.getMessage(WorkReportDailyEnum.REPORT_DATE.getAttrName()),date));
        jsonArray.add(new ItemDataPoJo(I18nMessageUtil.getMessage(WorkReportDailyEnum.TYPE.getAttrName()),typeName));
        PaasFormEntityExt paasFormEntityExt = paasFormModel.getByBusinessType(workReportTypeEnum.getBusinessType(), coolAppWorkReportTopCardDTO.getCorpid());
        if (Objects.isNull(paasFormEntityExt)){
            LOG.info("---------paasFormEntityExt is null");
            return;
        }

        String writeWorkReportUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + coolAppWorkReportTopCardDTO.getCorpid() + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ coolAppWorkReportTopCardDTO.getOpenConversationId()+ "&dd_nav_bgcolor=ffff943e#";
        writeWorkReportUrl += String.format(CoolAppConstant.WRITE_WORK_REPORT_PAGE_URL,paasFormEntityExt.getAppId(), paasFormEntityExt.getMenuId(), paasFormEntityExt.getId(), cardDataEntity.getCardBizId(), paasFormEntityExt.getBusinessType());
        String pcWriteWorkReportUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(writeWorkReportUrl);
        String mobileWriteWorkReportUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(writeWorkReportUrl);

        // 按钮添加Url
        JSONObject buttons = cardTemplateExplainPojo.getButtons();
        JSONObject writeReport = buttons.getJSONObject("writeReport");
        writeReport.put("pcUrl",pcWriteWorkReportUrl);
        writeReport.put("mobileUrl",mobileWriteWorkReportUrl);
        buttons.clear();
        buttons.put("writeReport",writeReport);
        // 封装卡片数据
        Map<String, String> cardData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 标题
        cardData.put("title",title);
        cardData.put("rowsNum", "2");
        cardData.put("topCardType", TopCardTypeEnum.WORK_REPORT_REMIND.getAlias());
        Map<String, Map<String, String>> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (Object receverId : receiverUserIds) {
            Map<String, Object> tempCardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, String> tempCardPrivateData1 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            tempCardPrivateData.put("content",jsonArray);
            tempCardPrivateData.put("buttons", cardTemplateExplainPojo.getButtons());
            tempCardPrivateData1.put(COMPLEX_PARAM, JSON.toJSONString(tempCardPrivateData));
            cardPrivateData.put(String.valueOf(receverId),tempCardPrivateData1);
        }
        CardDataPojo cardDataPojo = new CardDataPojo(JSONArray.parseArray(receiverUserIds.toJSONString(),String.class), cardData, cardPrivateData);
        LOG.info("----------cardDataPojo:{}",JSON.toJSONString(cardDataPojo));
        String processQueryKey = bizManager.sendTopCard(accessToken, cardDataEntity, cardDataPojo);
        if (Objects.nonNull(processQueryKey)){
            cardDataEntity.setProcessQueryKey(processQueryKey);
            coolAppCardDataModel.update(cardDataEntity);
        }
    }

    public CoolAppCardDataEntity saveTopCardData(CoolAppWorkReportTopCardDTO coolAppWorkReportTopCardDTO,String cardId,JSONArray receiverUserIds, String creatorId, String parentCardBizId, Long sourceDataId, JSONObject processNode) throws XbbException {
        CoolAppCardDataEntity cardDataEntity = new CoolAppCardDataEntity();
        cardDataEntity.setCorpid(coolAppWorkReportTopCardDTO.getCorpid());
        cardDataEntity.setAppId(0L);
        cardDataEntity.setMenuId(0L);
        cardDataEntity.setFormId(0L);
        cardDataEntity.setSaasMark(1);
        cardDataEntity.setBusinessType(coolAppWorkReportTopCardDTO.getBusinessType());
        cardDataEntity.setDataId(0L);
        cardDataEntity.setCreatorId(creatorId);
        // 审批节点对应模板
        cardDataEntity.setProcessNode(processNode);

        // 开启跟进提醒保存关联客户数据id
        cardDataEntity.setSourceDataId(sourceDataId);

        cardDataEntity.setCardId(cardId);
        cardDataEntity.setOpenConversationId(coolAppWorkReportTopCardDTO.getOpenConversationId());
        cardDataEntity.setConversationType(BasicConstant.ONE);
        cardDataEntity.setRobotCode(proBaseConfig.getRobotCode());
        cardDataEntity.setCardBizId(UUID.randomUUID().toString());
        // parentCardBizId，默认为1
        cardDataEntity.setParentCardBizId(BasicConstant.ONE_STRING);
        if (Objects.nonNull(parentCardBizId)) {
            cardDataEntity.setParentCardBizId(parentCardBizId);
        }
        // 卡片接收人
        cardDataEntity.setReceiverUserIds(receiverUserIds);
        // 消息@人
        cardDataEntity.setAtUserIds(null);
        try {
            coolAppCardDataModel.insert(cardDataEntity);
        } catch (Exception e) {
            LOG.error("保存互动卡片失败！",e );
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, I18nMessageUtil.getMessage(ErrorMessageConstant.SAVE_ERROR));
        }
        return cardDataEntity;

    }

    /**
     * 获取没有提交报告的人数
     * @param coolAppWorkReportTopCardDTO
     * @return
     * @throws XbbException
     */
    public List<String> getNotHandReportUserIdList(CoolAppWorkReportTopCardDTO coolAppWorkReportTopCardDTO) throws XbbException {

        List<String> reportDate = coolAppWorkReportTopCardDTO.getReportDate();
        if(reportDate.isEmpty() || reportDate.size() < 2) {
            throw new XbbException(WorkReportErrorCodeEnum.API_ERROR_207018);
        }

        String corpid = coolAppWorkReportTopCardDTO.getCorpid();
        String userId = coolAppWorkReportTopCardDTO.getUserId();
        Integer reportType = coolAppWorkReportTopCardDTO.getReportType();


        if (DateUtil.getInt(reportDate.get(0), new SimpleDateFormat("yyyy-MM-dd")) > DateUtil.getInt(reportDate.get(1), new SimpleDateFormat("yyyy-MM-dd"))){
            throw new XbbException(WorkReportErrorCodeEnum.API_ERROR_207019);
        }
        List<String> userIdList;
        try {
            userIdList = workReportSetService.settingUsersFilter(corpid, coolAppWorkReportTopCardDTO.getReportType());
            // 不统计自己
            if(userIdList.contains(userId)) {
                userIdList.remove(userId);
            }

            List<String> selectUserList = getUserList(corpid,userId,coolAppWorkReportTopCardDTO.getPid(),coolAppWorkReportTopCardDTO.getTreeType(), reportType);
            if(Objects.nonNull(selectUserList)) {
                userIdList.retainAll(selectUserList);
            }
            if(userIdList.isEmpty()) {
                throw new XbbException(WorkReportErrorCodeEnum.API_ERROR_207020);
            }

            // 工作报告类型
            WorkReportTypeEnum reportTypeEnum = WorkReportTypeEnum.getByType(reportType);
            PaasFormEntityExt paasFormEntityExt = paasFormModel.getByBusinessType(reportTypeEnum.getBusinessType() ,corpid);
            if (Objects.isNull(paasFormEntityExt)) {
                throw new XbbException(WorkReportErrorCodeEnum.API_ERROR_207021);
            }

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword",corpid ));
            boolQueryBuilder.filter(termsQuery(FieldTypeEnum.CREATORID.getAlias() + StringConstant.POINT + StringConstant.KEY_WORD,userIdList));
            boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
            boolQueryBuilder.filter(rangeQuery("data." +  WorkReportFieldEnum.REPORT_DATE.getAttr()).gte(DateUtil.getInt(reportDate.get(0),new SimpleDateFormat("yyyy-MM-dd"))).lt(DateUtil.getInt(reportDate.get(1),new SimpleDateFormat("yyyy-MM-dd"))));
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_WORK_REPORT.getType()));
            sourceBuilder.sort(new FieldSortBuilder("data." +  WorkReportFieldEnum.REPORT_DATE.getAttr()).order(SortOrder.ASC));
            sourceBuilder.query(boolQueryBuilder);
            SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_WORK_REPORT.getIndex());
            PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 0, userIdList.size());
            searchRequest.source(sourceBuilder);
            XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, PaasFormDataEntityExt.class);
            List<String> doneUserIds = new ArrayList<>();
            for (PaasFormDataEntityExt entity : esEntities.getContent()){
                if(userIdList.contains(entity.getCreatorId())) {
                    doneUserIds.add(entity.getCreatorId());
                }
            }
            userIdList.removeAll(doneUserIds);
        } catch (Exception e) {
            LOG.debug("获取未交人员失败", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }

        return userIdList;
    }

    private List<String> getUserList(String corpid, String userId, String pid, String treeType,Integer reportType) {
        // 在工作报告使用范围内的用户
        List<String> userIdList = workReportSetService.settingUsersFilter(corpid,reportType);
        UserEntity user = userModel.getByKey(userId, corpid);
        // 统计自己下属的用户
        Integer dataPermission = userModel.getDataPermission(user, SaasMarkEnum.SAAS, XbbRefTypeEnum.WORK_REPORT.getCode(), null);
        List<String> subUserList = userModel.getSubIdListByDataPermission(dataPermission, userId, corpid, BasicConstant.ZERO, true);
        // 取userIdList与subUserList交集为统计的人员
        userIdList.retainAll(subUserList);
        if (userIdList.size() < 1){
            return null;
        }
        if (!StringUtil.isEmpty(pid) && !StringUtil.isEmpty(treeType)){
            List<String> searchUserIdList = new ArrayList<>();
            if (Objects.equals(treeType,"staff")){
                searchUserIdList.add(pid);
            }else if (Objects.equals(treeType,"department")){
                searchUserIdList = userModel.getUserIdsRecursionDep(Collections.singletonList(Long.valueOf(pid)),corpid);
            }
            userIdList.retainAll(searchUserIdList);
        }
        //统计排除自身,原saas逻辑,也不知道为什么
        userIdList.remove(userId);
        if (userIdList.isEmpty()){
            userIdList.add("-1");
        }
        return userIdList;
    }

    @Override
    public BaseVO updateCard(CoolAppUpdateCardDTO coolAppUpdateCardDTO) throws XbbException {
        BaseVO baseVO = new BaseVO();
        String corpid = coolAppUpdateCardDTO.getCorpid();
        Integer businessType = coolAppUpdateCardDTO.getBusinessType();
        Long dataId = coolAppUpdateCardDTO.getDataId();
        String cardBizId = coolAppUpdateCardDTO.getCardBizId();
        String openConversationId = coolAppUpdateCardDTO.getOpenConversationId();
        openConversationId = CoolAppCardUtil.decodeOpenConversationId(openConversationId);
        coolAppUpdateCardDTO.setOpenConversationId(openConversationId);
        if (StringUtil.isEmpty(cardBizId)){
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520008);
        }
        // 群id不能为空
        if (StringUtil.isEmpty(openConversationId)) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520001);
        }
        // 酷应用：不能为空或卸载
        DingBundleEntity dingBundleEntity = dingBundleModel.getByType(corpid, openConversationId, DingBundleTypeEnum.COOL_APP.getCode());
        if (Objects.isNull(dingBundleEntity) || Objects.equals(dingBundleEntity.getStatus(), DingBundleStatusEnum.DISMISS.getCode())) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520002);
        }
        // 只有客户、合同、跟进记录、跟进记录评论回复
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        boolean noNeedCardFlag = !(xbbRefTypeEnum == XbbRefTypeEnum.CUSTOMER_MANAGEMENT || xbbRefTypeEnum == XbbRefTypeEnum.CONTRACT || xbbRefTypeEnum == XbbRefTypeEnum.CUSTOMER_COMMUNICATE
                || xbbRefTypeEnum == XbbRefTypeEnum.SALES_OPPORTUNITY || xbbRefTypeEnum == XbbRefTypeEnum.COMMUNICATE_PLAN || xbbRefTypeEnum == XbbRefTypeEnum.WORK_REPORT);
        if (noNeedCardFlag) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520003);
        }
        HashMap<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        map.put(StringConstant.CORPID,corpid);
        map.put("cardBizId",cardBizId);
        map.put("openConversationId",openConversationId);
        List<CoolAppCardDataEntity> cardDataEntities = coolAppCardDataModel.findEntitys(map);
        if (CollectionsUtil.isEmpty(cardDataEntities)){
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520007);
        }
        CoolAppCardDataEntity coolAppCardDataEntity = cardDataEntities.get(0);
        String cardId = coolAppCardDataEntity.getCardId();
        if (Objects.isNull(dataId)){
            dataId = coolAppCardDataEntity.getDataId();
        }

        // 获取卡片模板
        map.clear();
        map.put("cardId",cardId);
        List<CoolAppCardTemplateEntity> coolAppCardTemplateEntities = coolAppCardTemplateModel.findEntitys(map);
        if (CollectionsUtil.isEmpty(coolAppCardTemplateEntities)){
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520004);
        }
        CoolAppCardTemplateEntity coolAppCardTemplateEntity = coolAppCardTemplateEntities.get(0);
        Integer useScene = coolAppCardTemplateEntity.getUseScene();
        CardUseSceneEnum cardUseSceneEnum = CardUseSceneEnum.getByType(useScene);
        businessType = coolAppCardDataEntity.getBusinessType();
        PaasFormDataEntityExt paasFormDataEntityExt = saasGetHelp.getFormData(dataId, corpid, businessType);
        if (Objects.isNull(paasFormDataEntityExt)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
        }

        update(corpid,paasFormDataEntityExt,coolAppCardDataEntity,coolAppCardTemplateEntity,cardUseSceneEnum,coolAppUpdateCardDTO);
        
        return baseVO;
    }

    @Override
    public BaseVO sendProcessCard(CoolAppWorkflowCardDTO coolAppWorkflowCardDTO) throws XbbException {
        return coolAppProcessCardService.sendProcessCard(coolAppWorkflowCardDTO);
    }

    @Override
    public BaseVO updateProcessCard(CoolAppWorkflowCardDTO coolAppWorkflowCardDTO) throws XbbException {
        // 酷应用：钉钉平台特性
        if (!coolAppWorkflowCardDTO.getCorpid().startsWith("ding")) {
            return new BaseVO();
        }
        String corpid = coolAppWorkflowCardDTO.getCorpid();
        Integer businessType = coolAppWorkflowCardDTO.getBusinessType();
        Long formId = coolAppWorkflowCardDTO.getFormId();
        Long taskId = coolAppWorkflowCardDTO.getTaskId();
        Long preTaskId = coolAppWorkflowCardDTO.getPreTaskId();
        String operatorId = coolAppWorkflowCardDTO.getUserId();
        Integer flowStatus = coolAppWorkflowCardDTO.getFlowStatus();

        TaskTypeEnum taskTypeEnum = TaskTypeEnum.getTaskTypeEnum(coolAppWorkflowCardDTO.getTaskType());
        if (Objects.isNull(taskTypeEnum)) {
            return new BaseVO();
        }

        // 只有客户、合同、跟进记录、跟进记录评论回复
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        boolean noNeedCardFlag = !(xbbRefTypeEnum == XbbRefTypeEnum.CUSTOMER_MANAGEMENT || xbbRefTypeEnum == XbbRefTypeEnum.CONTRACT || xbbRefTypeEnum == XbbRefTypeEnum.CUSTOMER_COMMUNICATE
                || xbbRefTypeEnum == XbbRefTypeEnum.SALES_OPPORTUNITY || xbbRefTypeEnum == XbbRefTypeEnum.COMMUNICATE_PLAN || xbbRefTypeEnum == XbbRefTypeEnum.WORK_REPORT);
        if (noNeedCardFlag) {
            return new BaseVO();
        }

        List<CoolAppCardDataEntity> list = new ArrayList<>();
        // 重新提交处理
        if (TaskTypeEnum.AGAIN_COMMIT == taskTypeEnum) {
            if (Objects.isNull(preTaskId)) {
                return new BaseVO();
            }
            // 获取数据
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(StringConstant.CORPID, corpid);
            param.put(StringConstant.FORM_ID, formId);
            param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            param.put("processTaskId", preTaskId);
            param.put("parentCardBizId", BasicConstant.ONE);
            param.put("orderByStr", "update_time desc");
            List<CoolAppCardDataEntity> oldList = coolAppCardDataModel.findEntitys(param);
            if (CollectionsUtil.isEmpty(oldList)) {
                return new BaseVO();
            }
            // 每个群只取第一份
            Set<String> openConversationIdSet = new HashSet<>();
            for (CoolAppCardDataEntity coolAppCardDataEntity : oldList) {
                if (openConversationIdSet.contains(coolAppCardDataEntity.getOpenConversationId())) {
                    continue;
                }
                openConversationIdSet.add(coolAppCardDataEntity.getOpenConversationId());
                list.add(coolAppCardDataEntity);
            }
        } else {
            // 获取数据
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(StringConstant.CORPID, corpid);
            param.put(StringConstant.FORM_ID, formId);
            param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            param.put("processTaskId", taskId);
            param.put("flowStatus", FlowStatusEnum.APPROVAL_PENDING.getType());
            list = coolAppCardDataModel.findEntitys(param);
        }

        if (CollectionsUtil.isEmpty(list)) {
            return new BaseVO();
        }

        // 获取群id
        Set<String> openConversationIdSet = new HashSet<>();
        list.forEach(item -> {
            openConversationIdSet.add(item.getOpenConversationId());
        });
        // 过滤已关闭的群
        Map<String, Object> openConversationParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        openConversationParam.put(StringConstant.CORPID, corpid);
        openConversationParam.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
        openConversationParam.put("openConversationIdIn", openConversationIdSet);
        openConversationParam.put("type", DingBundleTypeEnum.COOL_APP.getCode());
        List<DingBundleEntity> dingBundleList = dingBundleModel.findEntitys(openConversationParam);
        if (CollectionsUtil.isEmpty(dingBundleList)) {
            return new BaseVO();
        }
        openConversationIdSet.clear();
        dingBundleList.forEach(item -> {
            if (Objects.equals(DingBundleStatusEnum.NORMAL.getCode(), item.getStatus())) {
                openConversationIdSet.add(item.getOpenConversationId());
            }
        });

        // 过滤卡片
        list.removeIf(item -> !openConversationIdSet.contains(item.getOpenConversationId()));
        if (CollectionsUtil.isEmpty(list)) {
            return new BaseVO();
        }

        // 获取审批卡片审批
        CoolAppCardTemplateEntity cardTemplateEntity = coolAppCardTemplateModel.getByUseScene(CardTypeEnum.IM_CARD.getType(), CardUseSceneEnum.PROCESS_OR_WORKFLOW.getType());

        List<CoolAppCardDataEntity> topCardList = new ArrayList<>();
        List<CoolAppCardDataEntity> cardList = new ArrayList<>();
        list.forEach(item -> {
            if (Objects.equals(item.getCardId(), cardTemplateEntity.getCardId())) {
                cardList.add(item);
            } else {
                topCardList.add(item);
            }
        });

        long now = DateTimeUtil.getInt();
        // 更新数据
        if (TaskTypeEnum.STORAGE != taskTypeEnum) {
            list.forEach(item -> {
                item.setFlowStatus(FlowStatusEnum.PASS.getType());
                item.setUpdateTime(now);
            });
            coolAppCardDataModel.updateBatch(list, corpid);
        }

        boolean workFlow = commonHelp.isOpenWorkFlow(corpid);

        updateProcessOrWorkFlowCard(corpid ,topCardList, cardList, coolAppWorkflowCardDTO, taskTypeEnum, operatorId, flowStatus, workFlow);

        return new BaseVO();
    }

    @Override
    public BaseVO sendCommunicateTopCard(CoolAppSendRemindTopCardDTO coolAppSendRemindTopCardDTO) throws XbbException {
        String corpid = coolAppSendRemindTopCardDTO.getCorpid();
        Long customerDataId = coolAppSendRemindTopCardDTO.getRefId();
        Long pushTime = coolAppSendRemindTopCardDTO.getPushTime();
        String pushObject = coolAppSendRemindTopCardDTO.getPushObject();
        List<String> pushArray = JsonHelperUtil.parseArray(pushObject, String.class);
        // 跟进提醒推送人只有一个
        if (pushArray.size() != 1){
            return null;
        }
        JSONObject msg = JsonHelperUtil.parseObject(coolAppSendRemindTopCardDTO.getMsg());
        JSONObject body = msg.getJSONObject("body");
        // 推送内容
        String content = body.getString("content");

        HashMap<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        map.put(StringConstant.CORPID,corpid);
        map.put("sourceDataId",customerDataId);
        map.put("businessType", XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode());
        map.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
        List<CoolAppCardDataEntity> dataEntityList = coolAppCardDataModel.findEntitys(map);
        if (CollectionsUtil.isEmpty(dataEntityList)){
            return null;
        }
        List<Long> idIn = new ArrayList<>();
        dataEntityList.forEach(item -> idIn.add(item.getDataId()));
        List<CustomerCommunicateEntityExt> communicateEntityExtList = customerCommunicateModel.getByIdIn(idIn, corpid);
        if (CollectionsUtil.isEmpty(communicateEntityExtList)){
            return null;
        }
        Map<Long, CustomerCommunicateEntityExt> communicateMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        communicateEntityExtList.forEach(item -> communicateMap.put(item.getId(),item));
        // 跟进记录id
        Long targetId = 0L;
        CustomerCommunicateEntityExt communicateEntityExt = null;
        CoolAppCardDataEntity coolAppCardDataEntity = null;
        for (CoolAppCardDataEntity cardDataEntity : dataEntityList) {
            Long id = cardDataEntity.getDataId();
            communicateEntityExt = communicateMap.get(id);
            if (Objects.isNull(communicateEntityExt)){
                continue;
            }
            JSONObject data = communicateEntityExt.getData();
            Integer isRemind = FastJsonHelper.getIntegerOrDefault(data, CustomerCommunicateEnum.IF_REMIND.getAttr(), 0);
            if (isRemind != 1){
                continue;
            }
            Long dataId =  data.getLong(CustomerCommunicateEnum.CUSTOMER_NAME.getAttr());
            // 关联客户id ref_id == data_id
            if (!Objects.equals(dataId,customerDataId)){
                continue;
            }
            // 提醒时间 push_time == notifyTime
            Long notifyTime = data.getLong(CustomerCommunicateEnum.NOTIFY_TIME.getAttr());
            if (!Objects.equals(notifyTime,pushTime)){
                continue;
            }
            // 接收人 push_object == receiver_user_ids
            String creatorId = communicateEntityExt.getCreatorId();
            if (!Objects.equals(creatorId,pushArray.get(0))){
                continue;
            }
            // 推送内容 msg--body--content == nextNotifyMemo
            String nextNotifyMemo = data.getString(CustomerCommunicateEnum.NEXT_NOTIFY_MEMO.getAttr());
            if (Objects.equals(content,nextNotifyMemo)){
                targetId = id;
                coolAppCardDataEntity = cardDataEntity;
            }
        }
        if (Objects.isNull(coolAppCardDataEntity)) {
            return null;
        }
        CoolAppCardTemplateEntity cardTemplateEntity = coolAppCardTemplateModel.getByUseScene(CardTypeEnum.TOP_CARD.getType(), CardUseSceneEnum.TOP_CARD.getType());

        try {
            sendCommunicateTopCard(cardTemplateEntity, communicateEntityExt, corpid, targetId, coolAppCardDataEntity);
        } catch (Exception e) {
            LOG.error("发送吊顶卡片失败", e);
        }

        return new BaseVO();
    }

    @Override
    public BaseVO sendCommunicatePlanTopCard(CoolAppSendRemindTopCardDTO coolAppSendRemindTopCardDTO) throws XbbException {
        String corpid = coolAppSendRemindTopCardDTO.getCorpid();
        Long planDataId = coolAppSendRemindTopCardDTO.getRefId();
        Integer type = coolAppSendRemindTopCardDTO.getType();

        HashMap<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        map.put(StringConstant.CORPID,corpid);
        map.put("dataId",planDataId);
        map.put("businessType", XbbRefTypeEnum.COMMUNICATE_PLAN.getCode());
        map.put("sourceDataId", planDataId);
        map.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
        List<CoolAppCardDataEntity> dataEntityList = coolAppCardDataModel.findEntitys(map);
        if (CollectionsUtil.isEmpty(dataEntityList)){
            LOG.info("-------------dataEntityList is null");
            return null;
        }
        CoolAppCardDataEntity coolAppCardDataEntity = dataEntityList.get(0);
        CoolAppCardTemplateEntity cardTemplateEntity = coolAppCardTemplateModel.getByUseScene(CardTypeEnum.TOP_CARD.getType(), CardUseSceneEnum.TOP_CARD.getType());

        CommunicatePlanEntityExt communicatePlanEntityExt = communicatePlanModel.getByKey(planDataId, corpid);
        if (Objects.isNull(communicatePlanEntityExt)){
            LOG.info("-------------communicatePlanEntityExt is null");
            return null;
        }
        try {
            sendCommunicatePlanTopCard(cardTemplateEntity, corpid, coolAppSendRemindTopCardDTO, communicatePlanEntityExt, coolAppCardDataEntity);
        } catch (Exception e) {
            LOG.error("发送访客计划吊顶卡片失败", e);
        }

        return null;
    }

    @Override
    public BaseVO closeTopCard(CoolAppCloseCardDTO coolAppCloseCardDTO) throws XbbException {
        // 卡片数据
        String corpid = coolAppCloseCardDTO.getCorpid();
        CoolAppCardDataEntity cardDataEntity = coolAppCardDataModel.getByCardBizId(corpid, coolAppCloseCardDTO.getCardBizId());
        if (Objects.isNull(cardDataEntity)) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520006);
        }
        // 获取卡片模板
        CoolAppCardTemplateEntity cardTemplateEntity = coolAppCardTemplateModel.getByCardId(cardDataEntity.getCardId());
        if (Objects.isNull(cardTemplateEntity)) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520004);
        }
        if (!Objects.equals(CardTypeEnum.TOP_CARD.getType(), cardTemplateEntity.getCardType())) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520009);
        }

        String accessToken;
        try {
            accessToken = authHelper.getAccessToken(corpid);
        } catch (OApiException e) {
            LOG.error("获取accessToken失败");
            return new BaseVO();
        }

        bizManager.closeTopCard(accessToken, cardDataEntity, null);

        return new BaseVO();
    }

    @Override
    public BaseVO initCoolAppBundle(MenuInitDTO menuInitDTO) throws XbbException {
        AppModuleEntity appModule = appModuleModel.getByAlias(SystemAppMenuEnum.BUNDLE.getAlias());
        menuInitDTO.setName(appModule.getName());
        menuInitDTO.setIcon(appModule.getIcon());
        initMenuHelp.menuInit(menuInitDTO);
        return new BaseVO();
    }

    public void sendCommunicateTopCard(CoolAppCardTemplateEntity coolAppCardTemplateEntity, CustomerCommunicateEntityExt communicateEntityExt, String corpid, Long targetId,CoolAppCardDataEntity coolAppCardDataEntity){
        Runnable runnable = () -> {
            String accessToken;
            try {
                accessToken = authHelper.getAccessToken(corpid);
            } catch (OApiException e) {
                return;
            }
            JSONObject explain = coolAppCardTemplateEntity.getExplain();
            CardTemplateExplainPojo cardTemplateExplainPojo = explain.toJavaObject(CardTemplateExplainPojo.class);
            // 卡片接收人
            String creatorId = communicateEntityExt.getCreatorId();
            JSONArray receverIds = new JSONArray();
            receverIds.add(creatorId);
            coolAppCardDataEntity.setReceiverUserIds(receverIds);
            JSONObject data = communicateEntityExt.getData();
            String customerName = data.getString(CustomerCommunicateEnum.CUSTOMER_NAME_LINK_TEXT.getAttr());
            String title = customerName + "的跟进提醒";

            JSONArray jsonArray = new JSONArray();
            String nextNotifyMemo = data.getString(CustomerCommunicateEnum.NEXT_NOTIFY_MEMO.getAttr());
            Long time = data.getLong(CustomerCommunicateEnum.NEXT_COMMUNICATE_TIME.getAttr());
            String nextNotifyTime = DateTimeUtil.getStringEpochSecond(time, DateTimeUtil.SDF);

            jsonArray.add(new ItemDataPoJo(I18nMessageUtil.getMessage(CustomerCommunicateEnum.NEXT_COMMUNICATE_TIME.getAttrName()),nextNotifyTime));
            jsonArray.add(new ItemDataPoJo(I18nMessageUtil.getMessage(CustomerCommunicateEnum.NEXT_NOTIFY_MEMO.getAttrName()),nextNotifyMemo));

            // 获取跟进记录关联客户
            String customerId = data.getString(CustomerCommunicateEnum.CUSTOMER_NAME.getAttr());
            CustomerEntityExt customerEntityExt = customerModel.getByKey(Long.valueOf(customerId), corpid);
            if (Objects.isNull(customerEntityExt)){
                return;
            }
            // 按钮url
            String writeFollowUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ coolAppCardDataEntity.getOpenConversationId()+ "&dd_nav_bgcolor=ffff943e#";
            String detailUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ coolAppCardDataEntity.getOpenConversationId()+ "&dd_nav_bgcolor=ffff943e#";
            writeFollowUrl += String.format(CoolAppConstant.CUSTOMER_DETAIL_PAGE_URL, customerEntityExt.getId(), customerEntityExt.getAppId(), customerEntityExt.getMenuId(), customerEntityExt.getFormId(),coolAppCardDataEntity.getCardBizId());
            detailUrl += String.format(CoolAppConstant.CUSTOMER_COMMUNICATE_DETAIL_PAGE_URL, targetId,communicateEntityExt.getAppId(), communicateEntityExt.getMenuId(), communicateEntityExt.getFormId(), coolAppCardDataEntity.getCardBizId());
            String pcWriteFollowUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(writeFollowUrl + "&coolAppOperate=" + CoolAppButtonOperateEnum.FOLLOW_UP.getAlias() + "&closeCoolCard=1");
            String mobileWriteFollowUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(writeFollowUrl + "&coolAppOperate=" + CoolAppButtonOperateEnum.FOLLOW_UP.getAlias() + "&closeCoolCard=1");
            String pcDetailUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl);
            String mobileDetailUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl);
            // 按钮添加Url
            JSONObject buttons = cardTemplateExplainPojo.getButtons();
            JSONObject writeFollow = buttons.getJSONObject("writeFollow");
            writeFollow.put("pcUrl",pcWriteFollowUrl);
            writeFollow.put("mobileUrl",mobileWriteFollowUrl);
            JSONObject detail = buttons.getJSONObject("detail");
            detail.put("pcUrl",pcDetailUrl);
            detail.put("mobileUrl",mobileDetailUrl);
            buttons.clear();
            buttons.put("writeFollow", writeFollow);
            buttons.put("detail", detail);
            // 封装卡片数据
            Map<String, String> cardData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            // 标题
            cardData.put("title",title);
            cardData.put("rowsNum", "2");
            cardData.put("topCardType", TopCardTypeEnum.COMMUNICATE_REMIND.getAlias());
            Map<String, Map<String, String>> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (Object receverId : receverIds) {
                Map<String, Object> tempCardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String, String> tempCardPrivateData1 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                tempCardPrivateData.put("content",jsonArray);
                tempCardPrivateData.put("buttons", cardTemplateExplainPojo.getButtons());
                tempCardPrivateData1.put(COMPLEX_PARAM, JSON.toJSONString(tempCardPrivateData));
                cardPrivateData.put(String.valueOf(receverId),tempCardPrivateData1);
            }
            CardDataPojo cardDataPojo = new CardDataPojo(Collections.singletonList(creatorId), cardData, cardPrivateData);
            String processQueryKey = bizManager.sendTopCard(accessToken, coolAppCardDataEntity, cardDataPojo);
            if (Objects.nonNull(processQueryKey)){
                coolAppCardDataEntity.setProcessQueryKey(processQueryKey);
                coolAppCardDataModel.update(coolAppCardDataEntity);
            }
        };
        threadPoolBeanConfig.interactiveCardThreadPool().execute(runnable);
    }

    public void sendCommunicatePlanTopCard(CoolAppCardTemplateEntity coolAppCardTemplateEntity, String corpid, CoolAppSendRemindTopCardDTO coolAppSendRemindTopCardDTO, CommunicatePlanEntityExt communicatePlanEntityExt, CoolAppCardDataEntity cardDataEntity){
        Runnable runnable = () -> {
            String accessToken;
            try {
                accessToken = authHelper.getAccessToken(corpid);
            } catch (OApiException e) {
                accessToken = null;
            }

            JSONObject explain = coolAppCardTemplateEntity.getExplain();
            CardTemplateExplainPojo cardTemplateExplainPojo = explain.toJavaObject(CardTemplateExplainPojo.class);
            // 卡片接收人
            String pushObject = coolAppSendRemindTopCardDTO.getPushObject();
            JSONArray receverUserIds = JSONArray.parseArray(pushObject);
            // 获取群成员
            List<String> groupMembers = dingCoolAppHelper.getGroupMembers(accessToken, cardDataEntity.getOpenConversationId(), proBaseConfig.getCoolAppCode());
            List<String> userIds = receverUserIds.toJavaList(String.class);
            //取交集
            userIds.retainAll(groupMembers);
            if (CollectionsUtil.isEmpty(userIds)) {
                LOG.error("卡片无接收人");
                return;
            }
            cardDataEntity.setReceiverUserIds(JSONArray.parseArray(JSON.toJSONString(userIds)));
            JSONObject data = communicatePlanEntityExt.getData();
            String customerId = data.getString(CommunicatePlanEnum.LINK_CUSTOMER.getAttr());
            CustomerEntityExt customerEntityExt = customerModel.getByKey(Long.valueOf(customerId), corpid);
            if (Objects.isNull(customerEntityExt)){
                LOG.info("----------customerEntityExt is null");
                return;
            }
            JSONObject data1 = customerEntityExt.getData();
            String customerName = data1.getString(CustomerManagementEnum.NAME.getAttr());
            String title = customerName + "的访客计划";

            JSONArray jsonArray = new JSONArray();
            Long time = data.getLong(CommunicatePlanEnum.COMMUNICATE_TIME.getAttr());
            String memo = data.getString(CustomerCommunicateEnum.MEMO.getAttr());
            String communicateTime = DateTimeUtil.getStringEpochSecond(time, DateTimeUtil.SDF);

            jsonArray.add(new ItemDataPoJo(I18nMessageUtil.getMessage(CommunicatePlanEnum.LINK_CUSTOMER.getAttrName()),customerName));
            jsonArray.add(new ItemDataPoJo(I18nMessageUtil.getMessage(CommunicatePlanEnum.COMMUNICATE_TIME.getAttrName()),communicateTime));
            jsonArray.add(new ItemDataPoJo(I18nMessageUtil.getMessage(CommunicatePlanEnum.MEMO.getAttrName()),memo));

            // 按钮url
            String signInUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ cardDataEntity.getOpenConversationId()+ "&dd_nav_bgcolor=ffff943e#";
            String detailUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ cardDataEntity.getOpenConversationId()+ "&dd_nav_bgcolor=ffff943e#";
            signInUrl += String.format(CoolAppConstant.SIGNIN_PAGE_URL, cardDataEntity.getAppId(), cardDataEntity.getMenuId(), cardDataEntity.getCardBizId(), DateTimeUtil.getLong());
            detailUrl += String.format(CoolAppConstant.COMMUNICATE_PLAN_DETAIL_PAGE_URL, coolAppSendRemindTopCardDTO.getRefId(),cardDataEntity.getAppId(), cardDataEntity.getMenuId(), cardDataEntity.getFormId(), cardDataEntity.getCardBizId());
            String pcSignInUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(signInUrl);
            String mobileSignInUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(signInUrl);
            String pcDetailUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl);
            String mobileDetailUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl);
            // 按钮添加Url
            JSONObject buttons = cardTemplateExplainPojo.getButtons();
            JSONObject signIn = buttons.getJSONObject("signIn");
            signIn.put("pcUrl",pcSignInUrl);
            signIn.put("mobileUrl",mobileSignInUrl);
            JSONObject detail = buttons.getJSONObject("detail");
            detail.put("pcUrl",pcDetailUrl);
            detail.put("mobileUrl",mobileDetailUrl);
            buttons.clear();
            buttons.put("detail", detail);
            buttons.put("signIn", signIn);
            // 封装卡片数据
            Map<String, String> cardData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            // 标题
            cardData.put("title",title);
            cardData.put("rowsNum", "1");
            cardData.put("topCardType", TopCardTypeEnum.COMMUNICATE_PLAN_REMIND.getAlias());

            Map<String, Map<String, String>> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (Object receverId : userIds) {
                Map<String, Object> tempCardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String, String> tempCardPrivateData1 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                tempCardPrivateData.put("content",jsonArray);
                tempCardPrivateData.put("buttons", cardTemplateExplainPojo.getButtons());
                tempCardPrivateData1.put(COMPLEX_PARAM, JSON.toJSONString(tempCardPrivateData));
                cardPrivateData.put(String.valueOf(receverId),tempCardPrivateData1);
            }
            CardDataPojo cardDataPojo = new CardDataPojo(userIds, cardData, cardPrivateData);
            String processQueryKey = bizManager.sendTopCard(accessToken, cardDataEntity, cardDataPojo);
            if (Objects.nonNull(processQueryKey)){
                cardDataEntity.setProcessQueryKey(processQueryKey);
                coolAppCardDataModel.update(cardDataEntity);
            }
        };
        threadPoolBeanConfig.interactiveCardThreadPool().execute(runnable);
    }

    @Override
    public BaseVO sendWorkflowCard(CoolAppWorkflowCardDTO coolAppWorkflowCardDTO) throws XbbException {
        return sendProcessCard(coolAppWorkflowCardDTO);
    }

    @Override
    public BaseVO updateWorkflowCard(CoolAppWorkflowCardDTO coolAppWorkflowCardDTO) throws XbbException {
        return updateProcessCard(coolAppWorkflowCardDTO);
    }

    public void update(String corpid, PaasFormDataEntityExt paasFormDataEntityExt, CoolAppCardDataEntity cardDataEntity, CoolAppCardTemplateEntity coolAppCardTemplateEntity, CardUseSceneEnum cardUseSceneEnum, CoolAppUpdateCardDTO coolAppUpdateCardDTO) {
        Runnable runnable = () -> {
            try {
                String accessToken;
                try {
                    accessToken = authHelper.getAccessToken(corpid);
                } catch (OApiException e) {
                    accessToken = null;
                }
                // 获取群成员
                List<String> groupMembers = dingCoolAppHelper.getGroupMembers(accessToken, cardDataEntity.getOpenConversationId(), proBaseConfig.getCoolAppCode());
                List<String> userIds = cardDataEntity.getReceiverUserIds().toJavaList(String.class);
                //取交集
                userIds.retainAll(groupMembers);
                //是否是全群成员
                boolean isAll = Objects.equals(userIds.size(), groupMembers.size()) && groupMembers.size() > BasicConstant.ZERO;

                // 更新对应卡片
                formatBusinessCardDataUpdate(corpid, accessToken, paasFormDataEntityExt, cardDataEntity.getFormId(), cardDataEntity.getDataId(), isAll, userIds, coolAppCardTemplateEntity.getExplain(), cardDataEntity, coolAppUpdateCardDTO);

            } catch (Exception e) {
                LOG.error("更新互动卡片失败", e);
            }
        };
        threadPoolBeanConfig.interactiveCardThreadPool().execute(runnable);
    }

    /**
     * 更新审批卡片
     *
     * @param corpid
     * @param topCardDataList
     * @param cardDataList
     * @param coolAppWorkflowCardDTO
     * @param taskTypeEnum
     * @param operatorId
     * @param flowStatus
     * @param workFlow
     */
    public void updateProcessOrWorkFlowCard(String corpid, List<CoolAppCardDataEntity> topCardDataList, List<CoolAppCardDataEntity> cardDataList,
                                            CoolAppWorkflowCardDTO coolAppWorkflowCardDTO, TaskTypeEnum taskTypeEnum, String operatorId, Integer flowStatus, boolean workFlow) {
        Runnable runnable = () -> {
            try {
                String accessToken;
                try {
                    accessToken = authHelper.getAccessToken(corpid);
                } catch (OApiException e) {
                    return;
                }

                switch (taskTypeEnum) {
                    case COMMIT:
                        commit(accessToken, corpid, topCardDataList, cardDataList, coolAppWorkflowCardDTO, operatorId, flowStatus, workFlow);
                        break;
                    case REVOKE:
                        revoke(accessToken, corpid, topCardDataList, cardDataList, coolAppWorkflowCardDTO, operatorId, workFlow);
                        break;
                    case BACK:
                        back(accessToken, corpid, topCardDataList, cardDataList, coolAppWorkflowCardDTO, operatorId, workFlow);
                        break;
                    case END:
                        end(accessToken, corpid, topCardDataList, cardDataList, coolAppWorkflowCardDTO, operatorId, workFlow);
                        break;
                    case TRANSFER:
                        transfer(accessToken, corpid, topCardDataList, cardDataList, coolAppWorkflowCardDTO, operatorId, workFlow);
                        break;
                    case STORAGE:
                        storage(accessToken, topCardDataList);
                        break;
                    case AGAIN_COMMIT:
                        againCommit(cardDataList, coolAppWorkflowCardDTO, flowStatus, workFlow);
                        break;
                    default:
                        break;
                }
            } catch (XbbException e) {
                // 不需要输出
            } catch (Exception e) {
                LOG.error("发送互动卡片失败", e);
            }
        };
        threadPoolBeanConfig.interactiveCardThreadPool().execute(runnable);
    }

    /**
     * 撤回审批
     *
     * @param accessToken
     * @param topCardDataList
     * @param cardDataList
     */
    private void revoke(String accessToken, String corpid, List<CoolAppCardDataEntity> topCardDataList, List<CoolAppCardDataEntity> cardDataList,
                        CoolAppWorkflowCardDTO coolAppWorkflowCardDTO, String operatorId, boolean workFlow) throws XbbException {
        // 关闭吊顶卡片
        for (CoolAppCardDataEntity cardDataEntity : topCardDataList) {
            bizManager.closeTopCard(accessToken, cardDataEntity, null);
        }
        // 修改卡片状态
        updateWorkflowCardData(accessToken, corpid, cardDataList, coolAppWorkflowCardDTO, operatorId, workFlow, CoolAppConstant.REVOKE, null);
    }

    /**
     * 审批结束
     *
     * @param accessToken
     * @param topCardDataList
     * @param cardDataList
     * @param operatorId
     */
    private void end(String accessToken, String corpid, List<CoolAppCardDataEntity> topCardDataList, List<CoolAppCardDataEntity> cardDataList,
                     CoolAppWorkflowCardDTO coolAppWorkflowCardDTO, String operatorId, boolean workFlow) throws XbbException {
        // 关闭吊顶卡片
        for (CoolAppCardDataEntity cardDataEntity : topCardDataList) {
            bizManager.closeTopCard(accessToken, cardDataEntity, null);
        }

        // 修改卡片状态
        updateWorkflowCardData(accessToken, corpid, cardDataList, coolAppWorkflowCardDTO, operatorId, workFlow, CoolAppConstant.REFUSED, null);
    }

    /**
     * 审批回退
     *
     * @param accessToken
     * @param topCardDataList
     * @param cardDataList
     * @param coolAppWorkflowCardDTO
     * @param operatorId
     * @param workFlow
     * @throws XbbException
     */
    private void back(String accessToken, String corpid, List<CoolAppCardDataEntity> topCardDataList, List<CoolAppCardDataEntity> cardDataList,
                      CoolAppWorkflowCardDTO coolAppWorkflowCardDTO, String operatorId, boolean workFlow) throws XbbException {
        // 关闭吊顶卡片
        for (CoolAppCardDataEntity cardDataEntity : topCardDataList) {
            bizManager.closeTopCard(accessToken, cardDataEntity, null);
        }

        // 更新原有卡片
        updateWorkflowCardData(accessToken, corpid, cardDataList, coolAppWorkflowCardDTO, operatorId, workFlow, CoolAppConstant.BACK, null);

        // 有多少群更新多少吊顶、互动卡片
        creatNewCard(topCardDataList, coolAppWorkflowCardDTO, workFlow, true);
    }

    /**
     * 审批提交（通过等操作）
     *
     * @param accessToken
     * @param topCardDataList
     * @param cardDataList
     * @param coolAppWorkflowCardDTO
     * @param operatorId
     * @param flowStatus
     * @param workFlow
     * @throws XbbException
     */
    private void commit(String accessToken, String corpid, List<CoolAppCardDataEntity> topCardDataList, List<CoolAppCardDataEntity> cardDataList,
                        CoolAppWorkflowCardDTO coolAppWorkflowCardDTO, String operatorId, Integer flowStatus, boolean workFlow) throws XbbException {
        // 关闭吊顶卡片
        for (CoolAppCardDataEntity cardDataEntity : topCardDataList) {
            bizManager.closeTopCard(accessToken, cardDataEntity, null);
        }

        FlowStatusEnum flowStatusEnum = FlowStatusEnum.getFlowStatusEnumByType(flowStatus);
        if (Objects.isNull(flowStatusEnum)) {
            return;
        }
        String resultStr = FlowStatusEnum.REJECT == flowStatusEnum ? CoolAppConstant.REFUSED : CoolAppConstant.PAAS;
        // 更新原有卡片
        updateWorkflowCardData(accessToken, corpid, cardDataList, coolAppWorkflowCardDTO, operatorId, workFlow, resultStr, flowStatus);
        if (FlowStatusEnum.IN_APPROVAL == flowStatusEnum) {
            // 有多少群更新多少吊顶、互动卡片
            creatNewCard(topCardDataList, coolAppWorkflowCardDTO, workFlow, false);
        } else if (FlowStatusEnum.PASS == flowStatusEnum) {
            // 抄送人发送互动卡片
            endCreatNewCard(topCardDataList, coolAppWorkflowCardDTO, workFlow);
        }
    }

    /**
     * 审批转交
     *
     * @param accessToken
     * @param topCardDataList
     * @param cardDataList
     * @param coolAppWorkflowCardDTO
     * @param operatorId
     * @param workFlow
     * @throws XbbException
     */
    private void transfer(String accessToken, String corpid, List<CoolAppCardDataEntity> topCardDataList, List<CoolAppCardDataEntity> cardDataList,
                          CoolAppWorkflowCardDTO coolAppWorkflowCardDTO, String operatorId, boolean workFlow) throws XbbException {
        // 关闭吊顶卡片
        for (CoolAppCardDataEntity cardDataEntity : topCardDataList) {
            bizManager.closeTopCard(accessToken, cardDataEntity, null);
        }

        // 更新原有卡片
        updateWorkflowCardData(accessToken,corpid, cardDataList, coolAppWorkflowCardDTO, operatorId, workFlow, CoolAppConstant.TRANSFER, null);

        // 有多少群生成多少吊顶、互动卡片
        creatNewCard(topCardDataList, coolAppWorkflowCardDTO, workFlow, false);
    }

    /**
     * 审批暂存
     *
     * @param accessToken
     * @param topCardDataList
     */
    private void storage(String accessToken, List<CoolAppCardDataEntity> topCardDataList) {
        // 关闭吊顶卡片
        for (CoolAppCardDataEntity cardDataEntity : topCardDataList) {
            bizManager.closeTopCard(accessToken, cardDataEntity, null);
        }
    }

    /**
     * 审批重新提交
     *
     * @param cardDataList
     * @param coolAppWorkflowCardDTO
     * @param workFlow
     * @throws XbbException
     */
    private void againCommit(List<CoolAppCardDataEntity> cardDataList, CoolAppWorkflowCardDTO coolAppWorkflowCardDTO, Integer flowStatus, boolean workFlow) throws XbbException {
        // 状态
        FlowStatusEnum flowStatusEnum = FlowStatusEnum.getFlowStatusEnumByType(flowStatus);
        if (Objects.isNull(flowStatusEnum)) {
            return;
        }
        if (FlowStatusEnum.APPROVAL_PENDING != flowStatusEnum) {
            return;
        }
        creatNewCard(cardDataList, coolAppWorkflowCardDTO, workFlow, true);
    }

    /**
     * 更新审批私有数据
     *
     * @param accessToken
     * @param corpid
     * @param cardDataList
     * @param operatorId
     * @param workFlow
     * @param approvalResult
     * @param flowStatus
     */
    private void updateWorkflowCardData(String accessToken,String corpid, List<CoolAppCardDataEntity> cardDataList, CoolAppWorkflowCardDTO coolAppWorkflowCardDTO,
                                        String operatorId, boolean workFlow, String approvalResult, Integer flowStatus) throws XbbException{

        for (CoolAppCardDataEntity cardDataEntity : cardDataList) {

            // 拼接dto
            CoolAppSendCardDTO coolAppSendCardDTO = new CoolAppSendCardDTO();
            BeanUtil.copyProperties(coolAppWorkflowCardDTO, coolAppSendCardDTO);
            coolAppSendCardDTO.setProcessTaskId(cardDataEntity.getProcessTaskId());
            coolAppSendCardDTO.setProcessNodeTaskId(cardDataEntity.getProcessNodeTaskId());

            CardDataProcessNode processNode = cardDataEntity.getProcessNode().toJavaObject(CardDataProcessNode.class);
            CardProcessWorkflowPojo cardProcessWorkflowPojo = new CardProcessWorkflowPojo();
            cardProcessWorkflowPojo.setWorkflow(workFlow);
            cardProcessWorkflowPojo.setProcessNode(processNode);

            // 获取审批节点、提交人节点数据
            List<Long> nodeTaskIds = new ArrayList<>();
            if (!processNode.getApproval().isEmpty()) {
                processNode.getApproval().forEach((userId, nodeTaskId) -> {
                    nodeTaskIds.add(nodeTaskId);
                });
            }
            if (!processNode.getCreator().isEmpty()) {
                processNode.getCreator().forEach((userId, nodeTaskId) -> {
                    nodeTaskIds.add(nodeTaskId);
                });
            }

            Map<String, Object> mainProcessNodeTaskMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, Object> ccProcessNodeTaskMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Object startNodeTask = null;
            if (workFlow) {
                List<WorkflowTaskNodeEntity> nodeTaskList = getWorkflowNodeTaskByIdIn(corpid, coolAppSendCardDTO.getFormId(),
                        coolAppSendCardDTO.getProcessTaskId(), coolAppWorkflowCardDTO.getWorkflowId(), nodeTaskIds);
                for (WorkflowTaskNodeEntity nodeTaskEntityExt : nodeTaskList) {
                    if (Objects.equals(nodeTaskEntityExt.getNodeType(), NodeTypeEnum.START_PROCESS_NODE.getNodeType())) {
                        startNodeTask = nodeTaskEntityExt;
                    } else {
                        mainProcessNodeTaskMap.put(nodeTaskEntityExt.getUserId(), nodeTaskEntityExt);
                    }
                }
                // 抄送人节点
                nodeTaskIds.clear();
                if (!processNode.getCc().isEmpty()) {
                    processNode.getCc().forEach((userId, nodeTaskId) -> {
                        nodeTaskIds.add(nodeTaskId);
                    });
                }
                nodeTaskList = getWorkflowNodeTaskByIdIn(corpid, coolAppSendCardDTO.getFormId(), coolAppSendCardDTO.getProcessTaskId(), coolAppWorkflowCardDTO.getWorkflowId(), nodeTaskIds);
                if (CollectionsUtil.isNotEmpty(nodeTaskList)) {
                    nodeTaskList.forEach(item -> {
                        ccProcessNodeTaskMap.put(item.getUserId(), item);
                    });
                }
            } else {
                List<PaasProcessNodeTaskEntityExt> nodeTaskList = getNodeTaskByIdIn(corpid, cardDataEntity.getProcessTaskId(), nodeTaskIds);
                for (PaasProcessNodeTaskEntityExt nodeTaskEntityExt : nodeTaskList) {
                    if (Objects.equals(nodeTaskEntityExt.getNodeType(), NodeTypeEnum.START_PROCESS_NODE.getNodeType())) {
                        startNodeTask = nodeTaskEntityExt;
                    } else {
                        mainProcessNodeTaskMap.put(nodeTaskEntityExt.getUserId(), nodeTaskEntityExt);
                    }
                }
                // 抄送人节点
                nodeTaskIds.clear();
                if (!processNode.getCc().isEmpty()) {
                    processNode.getCc().forEach((userId, nodeTaskId) -> {
                        nodeTaskIds.add(nodeTaskId);
                    });
                }
                nodeTaskList = getNodeTaskByIdIn(corpid, cardDataEntity.getProcessTaskId(), nodeTaskIds);
                if (CollectionsUtil.isNotEmpty(nodeTaskList)) {
                    nodeTaskList.forEach(item -> {
                        ccProcessNodeTaskMap.put(item.getUserId(), item);
                    });
                }
            }

            cardProcessWorkflowPojo.setStartNodeTask(startNodeTask);
            cardProcessWorkflowPojo.setMainProcessMap(mainProcessNodeTaskMap);
            cardProcessWorkflowPojo.setCcProcessMap(ccProcessNodeTaskMap);

            CardDataProcessUpdatePojo updatePojo = new CardDataProcessUpdatePojo(operatorId, approvalResult, flowStatus);
            CardDataPojo cardDataPojo = getProcessOrWorkflowCardData(corpid, cardDataEntity, coolAppSendCardDTO, cardProcessWorkflowPojo, null, false, updatePojo);
            if (Objects.isNull(cardDataPojo)) {
                throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520006);
            }
            bizManager.updateCard(accessToken, cardDataEntity.getCardBizId(), cardDataPojo);
        }
    }

    /**
     * 生成新的审批互动卡片、吊顶
     *
     * @param cardDataList
     * @param coolAppWorkflowCardDTO
     * @param workFlow
     * @param startNode
     * @throws XbbException
     */
    private void creatNewCard(List<CoolAppCardDataEntity> cardDataList, CoolAppWorkflowCardDTO coolAppWorkflowCardDTO,  boolean workFlow, boolean startNode) throws XbbException {
        if (CollectionsUtil.isEmpty(cardDataList)) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520007);
        }

        String corpid = coolAppWorkflowCardDTO.getCorpid();
        Long taskId = coolAppWorkflowCardDTO.getTaskId();
        // 人员
        CardProcessWorkflowPojo cardProcessWorkflowPojo = getProcessOrWorkflow(coolAppWorkflowCardDTO, workFlow, false);
        CardDataProcessNode processNode = cardProcessWorkflowPojo.getProcessNode();
        // 审批提交人、审批抄送人、审批人
        List<String> userIds = new ArrayList<>();
        userIds.add(cardProcessWorkflowPojo.getStartNodeUserId());
        userIds.addAll(cardProcessWorkflowPojo.getMainUserIds());
        userIds.addAll(cardProcessWorkflowPojo.getCcUserIds());


        // 审批卡片模板
        CoolAppCardTemplateEntity cardTemplateEntity = coolAppCardTemplateModel.getByUseScene(CardTypeEnum.IM_CARD.getType(), CardUseSceneEnum.PROCESS_OR_WORKFLOW.getType());
        CoolAppCardTemplateEntity topTemplateEntity = coolAppCardTemplateModel.getByUseScene(CardTypeEnum.TOP_CARD.getType(), CardUseSceneEnum.TOP_CARD.getType());

        // dto
        CoolAppSendCardDTO coolAppSendCardDTO = new CoolAppSendCardDTO();
        BeanUtil.copyProperties(coolAppWorkflowCardDTO, coolAppSendCardDTO);
        coolAppSendCardDTO.setProcessTaskId(taskId);
        coolAppSendCardDTO.setProcessNodeTaskId(cardProcessWorkflowPojo.getProcessNodeTaskId());
        coolAppSendCardDTO.setFlowStatus(FlowStatusEnum.APPROVAL_PENDING.getType());

        for (CoolAppCardDataEntity cardEntity : cardDataList) {
            coolAppSendCardDTO.setOpenConversationId(cardEntity.getOpenConversationId());
            // 生成新的卡片
            CoolAppCardDataEntity cardDataEntity;
            CoolAppCardDataEntity topCardDataEntity;
            String parentCardBizId = (startNode) ? null : cardEntity.getCardBizId();

            cardDataEntity = saveCardData(coolAppSendCardDTO, cardTemplateEntity.getCardId(),JSONArray.parseArray(JSON.toJSONString(userIds)), cardProcessWorkflowPojo.getStartNodeUserId(), parentCardBizId,null, JsonHelperUtil.parseObject(JSONObject.toJSONString(processNode)));
            topCardDataEntity = saveCardData(coolAppSendCardDTO, topTemplateEntity.getCardId(),JSONArray.parseArray(JSON.toJSONString(cardProcessWorkflowPojo.getMainUserIds())), cardProcessWorkflowPojo.getStartNodeUserId(), cardDataEntity.getCardBizId(),null, JsonHelperUtil.parseObject(JSONObject.toJSONString(processNode)));

            if (CollectionsUtil.isNotEmpty(userIds)) {
                sendProcessOrWorkflow(corpid, cardDataEntity, topCardDataEntity, coolAppSendCardDTO, cardProcessWorkflowPojo);
            }
        }
    }

    /**
     * 审批结束给抄送人发送卡片
     *
     * @param cardDataList
     * @param coolAppWorkflowCardDTO
     * @param workFlow
     * @throws XbbException
     */
    private void endCreatNewCard(List<CoolAppCardDataEntity> cardDataList, CoolAppWorkflowCardDTO coolAppWorkflowCardDTO,  boolean workFlow) throws XbbException {
        if (CollectionsUtil.isEmpty(cardDataList)) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520007);
        }

        String corpid = coolAppWorkflowCardDTO.getCorpid();
        Long taskId = coolAppWorkflowCardDTO.getTaskId();
        // 人员
        CardProcessWorkflowPojo cardProcessWorkflowPojo = getProcessOrWorkflow(coolAppWorkflowCardDTO, workFlow, true);
        List<String> ccUserIds = cardProcessWorkflowPojo.getCcUserIds();
        if (CollectionsUtil.isEmpty(ccUserIds)) {
            throw new XbbException(CoolAppErrorCodeEnum.API_ERROR_1520005);
        }
        CardDataProcessNode processNode = cardProcessWorkflowPojo.getProcessNode();
        // 获取抄送节点id
        Long ccNodeTaskId = processNode.getCc().get(ccUserIds.get(0));
        cardProcessWorkflowPojo.setProcessNodeTaskId(ccNodeTaskId);

        // 审批卡片模板
        CoolAppCardTemplateEntity cardTemplateEntity = coolAppCardTemplateModel.getByUseScene(CardTypeEnum.IM_CARD.getType(), CardUseSceneEnum.PROCESS_OR_WORKFLOW.getType());

        // dto
        CoolAppSendCardDTO coolAppSendCardDTO = new CoolAppSendCardDTO();
        BeanUtil.copyProperties(coolAppWorkflowCardDTO, coolAppSendCardDTO);
        coolAppSendCardDTO.setProcessTaskId(taskId);
        coolAppSendCardDTO.setProcessNodeTaskId(ccNodeTaskId);
        coolAppSendCardDTO.setFlowStatus(FlowStatusEnum.APPROVAL_PENDING.getType());

        for (CoolAppCardDataEntity cardEntity : cardDataList) {
            coolAppSendCardDTO.setOpenConversationId(cardEntity.getOpenConversationId());
            // 生成新的卡片
            CoolAppCardDataEntity cardDataEntity;
            cardDataEntity = saveCardData(coolAppSendCardDTO, cardTemplateEntity.getCardId(),JSONArray.parseArray(JSON.toJSONString(ccUserIds)), cardProcessWorkflowPojo.getStartNodeUserId(), null,null, JsonHelperUtil.parseObject(JSONObject.toJSONString(processNode)));
            if (CollectionsUtil.isNotEmpty(ccUserIds)) {
                sendProcessOrWorkflow(corpid, cardDataEntity, null, coolAppSendCardDTO, cardProcessWorkflowPojo);
            }
        }
    }



    /**
     * 获取审批节点
     *
     * @param corpid
     * @param taskId
     * @param nodeIds
     * @return
     */
    private List<PaasProcessNodeTaskEntityExt> getNodeTaskByIdIn(String corpid, Long taskId, List<Long> nodeIds) {
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put(StringConstant.CORPID, corpid);
        params.put("taskId", taskId);
        params.put("idIn", nodeIds);
        return paasProcessNodeTaskModel.findEntitys(params);
    }





    /**
     * 获取工作流节点
     *
     * @param corpid
     * @param formId
     * @param taskId
     * @param workflowId
     * @param nodeIds
     * @return
     */
    private List<WorkflowTaskNodeEntity> getWorkflowNodeTaskByIdIn(String corpid, Long formId, Long taskId, Long workflowId, List<Long> nodeIds) {
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.FORMID, formId);
        param.put("taskId", taskId);
        param.put("workflowId", workflowId);
        param.put("idIn", nodeIds);
        return workflowTaskNodeModel.findEntities(param);
    }

    private CardProcessWorkflowPojo getProcessOrWorkflow(CoolAppWorkflowCardDTO coolAppWorkflowCardDTO, boolean workflow, boolean isEnd) throws XbbException {
        return coolAppProcessCardService.getProcessOrWorkflow(coolAppWorkflowCardDTO, workflow, isEnd);
    }

    /**
     * 客户阶段推进器卡片接收人过滤
     *
     * @param explainMap
     * @param userIds
     * @param corpid
     * @param creatorId
     */
    public void addStageReceiverList(Map<String, FieldAttrEntity> explainMap, Set<String> userIds, String corpid, String creatorId, List<UserTeamEntity> userTeamEntities){
        //协同团队
        List<String> mainUserList = new ArrayList<>();
        List<String> coUserList = new ArrayList<>();
        userTeamEntities.forEach(item -> {
            if (Objects.equals(item.getIsMain(), BasicConstant.ONE)) {
                mainUserList.add(item.getUserId());
            } else {
                coUserList.add(item.getUserId());
            }
        });

        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
        handlerExplainDTO.setOwnerId(mainUserList);
        handlerExplainDTO.setCoUserId(mainUserList);
        handlerExplainDTO.setCreatorId(creatorId);
        List<String> userIdList = new ArrayList<>();
        userIdList.addAll(mainUserList);
        userIdList.addAll(coUserList);
        List<UserEntity> userList = userModel.getByUserId(userIdList, corpid);
        // 根据阶段字段可见权限添加接收人
        for (UserEntity userEntity : userList) {
            UserVO userVO = new UserVO();
            BeanUtil.copyProperties(userEntity, userVO);
            handlerExplainDTO.setLoginUser(userVO);
            handlerExplainDTO.setUserId(userVO.getUserId());
            boolean canSee = commonHelp.attrCanSee(CustomerManagementEnum.CUSTOMER_STAGE.getAttr(), explainMap, handlerExplainDTO);
            if (canSee){
                userIds.add(userEntity.getUserId());
            }
        }
    }

    /**
     * 客户、合同卡片接收人
     *
     * @param corpid 公司id
     * @param dataId 数据id
     * @param businessType 业务类型
     * @param userIds 接收人ids
     * @throws XbbException
     */
    public void getBusinessTeamMember(String corpid, Long dataId, Integer businessType, Set<String> userIds) {
        List<UserTeamEntity> userTeamEntities = userTeamHelp.getUserTeamList(Collections.singletonList(dataId), corpid, businessType, Boolean.FALSE, null);
        if (CollectionsUtil.isNotEmpty(userTeamEntities)) {
            userTeamEntities.forEach(item -> {userIds.add(item.getUserId());});
        }
    }

    /**
     * 跟进记录卡片接收人
     *
     * @param corpid 公司id
     * @param formId 客户表单id
     * @param dataId 客户数据id
     * @param userIds 接收人ids
     * @param creatorId 跟进记录创建人
     * @throws XbbException
     */
    public void getCustomerCommunicateTeamMember(String corpid, Long formId, Long dataId, Set<String> userIds, String creatorId) throws XbbException {
        // 表单共享标识，true：共享  false：隔离
        // 客户表单为空，不处理
        if (Objects.isNull(formId)) {
            return;
        }
        List<UserTeamEntity> userTeamEntities = userTeamHelp.getUserTeamList(Collections.singletonList(dataId), corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), Boolean.FALSE, null);
        if (CollectionsUtil.isEmpty(userTeamEntities)) {
            return;
        }
        boolean formShareTag = userTeamHelp.getFormShareTag(corpid, formId, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
        if (formShareTag) {
            userTeamEntities.forEach(item -> {userIds.add(item.getUserId());});
        } else {
            // 隔离模式
            Set<String> isolationOwnerSet = new HashSet<>();
            for (UserTeamEntity userTeamEntity : userTeamEntities) {
                if (Objects.equals(userTeamEntity.getIsMain(), BasicConstant.ONE)) {
                    isolationOwnerSet.add(userTeamEntity.getUserId());
                }
            }

            for (String userId : isolationOwnerSet) {
                List<String> teamUserIds = new ArrayList<>();
                for (UserTeamEntity userTeamEntity : userTeamEntities) {
                    // 非团队成员
                    if (!Objects.equals(userId, userTeamEntity.getUserId()) && !Objects.equals(userId, userTeamEntity.getTeamUserId())) {
                        continue;
                    }
                    teamUserIds.add(userTeamEntity.getUserId());
                }
                // 创建人是否在团队中
                if (CollectionsUtil.isNotEmpty(teamUserIds) && teamUserIds.contains(creatorId)) {
                    userIds.addAll(teamUserIds);
                }
            }
        }
    }

    /**
     * 发送互动卡片
     *
     * @param corpid 公司id
     * @param cardDataEntity 卡片数据
     * @param coolAppCardTemplateEntity 卡片模板
     */
    public void send(String corpid, PaasFormDataEntityExt paasFormDataEntityExt, CoolAppCardDataEntity cardDataEntity, CoolAppCardTemplateEntity coolAppCardTemplateEntity, CardUseSceneEnum cardUseSceneEnum ,CoolAppSendCardDTO coolAppSendCardDTO, PaasCommentEntity paasCommentEntity) {
        Runnable runnable = () -> {
            try {
                String accessToken;
                try {
                    accessToken = authHelper.getAccessToken(corpid);
                } catch (OApiException e) {
                    accessToken = null;
                }
                // 获取群成员
                List<String> groupMembers = dingCoolAppHelper.getGroupMembers(accessToken, cardDataEntity.getOpenConversationId(), proBaseConfig.getCoolAppCode());
                List<String> userIds = cardDataEntity.getReceiverUserIds().toJavaList(String.class);
                //取交集
                userIds.retainAll(groupMembers);
                //是否是全群成员
                boolean isAll = Objects.equals(userIds.size(), groupMembers.size()) && groupMembers.size() > BasicConstant.ZERO;
                if (CollectionsUtil.isEmpty(userIds)) {
                    LOG.error("卡片无接收人");
                    return;
                }
//                boolean isAll = false;
                String processQueryKey = "";
                switch (cardUseSceneEnum){
                    case BUSINESS:
                        processQueryKey = formatBusinessCardData(corpid, accessToken, paasFormDataEntityExt, cardDataEntity.getFormId(), cardDataEntity.getDataId(), isAll, userIds, coolAppCardTemplateEntity.getExplain(), cardDataEntity, coolAppSendCardDTO);
                        break;
                    case COMMUNICATE_REPLY:
                        processQueryKey = formatCommunicateReplyCardData(corpid, accessToken, paasFormDataEntityExt, cardDataEntity.getFormId(), cardDataEntity.getDataId(), isAll, userIds, coolAppCardTemplateEntity.getExplain(), cardDataEntity, coolAppSendCardDTO, paasCommentEntity);
                        break;
                    case STAGE:
                        processQueryKey = formatStageCardData(corpid, accessToken, paasFormDataEntityExt, cardDataEntity.getFormId(), cardDataEntity.getDataId(), isAll, userIds, coolAppCardTemplateEntity.getExplain(), cardDataEntity, coolAppSendCardDTO);
                        break;
                    default:
                        break;
                }
                if (Objects.nonNull(processQueryKey)) {
                    cardDataEntity.setProcessQueryKey(processQueryKey);
                    coolAppCardDataModel.update(cardDataEntity);
                }
            } catch (Exception e) {
                LOG.error("发送互动卡片失败", e);
            }
        };
        threadPoolBeanConfig.interactiveCardThreadPool().execute(runnable);
    }

    /**
     * 发送审批卡片
     *
     * @param corpid
     * @param cardDataEntity
     * @param topCardDataEntity
     * @param coolAppSendCardDTO
     * @param cardProcessWorkflowPojo
     */
    private void sendProcessOrWorkflow(String corpid, CoolAppCardDataEntity cardDataEntity, CoolAppCardDataEntity topCardDataEntity,
                                       CoolAppSendCardDTO coolAppSendCardDTO, CardProcessWorkflowPojo cardProcessWorkflowPojo) {
        coolAppProcessCardService.sendProcessOrWorkflow(corpid, cardDataEntity, topCardDataEntity, coolAppSendCardDTO, cardProcessWorkflowPojo);
    }


    public String formatCommunicateReplyCardData(String corpid,String accessToken, PaasFormDataEntityExt paasFormDataEntityExt, Long formId, Long dataId, boolean isAll, List<String> userIds,
                                                 JSONObject cardExplain, CoolAppCardDataEntity cardDataEntity, CoolAppSendCardDTO coolAppSendCardDTO, PaasCommentEntity paasCommentEntity) throws XbbException {
        CustomerCommunicateEntityExt customerCommunicateEntityExt = customerCommunicateModel.getByKey(paasCommentEntity.getRefId(), corpid);
        if (Objects.isNull(customerCommunicateEntityExt)){
            return null;
        }
        JSONObject data = customerCommunicateEntityExt.getData();
        // 客户名称
        Object customerName = data.get(CustomerCommunicateEnum.CUSTOMER_NAME_LINK_TEXT.getAttr());
        String loginUserName = coolAppSendCardDTO.getLoginUserName();
        String title = loginUserName + "评论了" + customerName + "的跟进记录";


        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(StringConstant.CORPID,corpid);
        param.put("user_id",coolAppSendCardDTO.getUserId());
        param.put("ref_id",dataId);
        param.put("type", BusinessCommentEnum.CUSTOMER_COMMUNICATE.getCode());
        param.put("orderByStr","add_time desc");
        param.put(StringConstant.DEL,BasicConstant.ZERO);
        List<PaasCommentEntityExt> list = paasCommentModel.list(param);
        if (CollectionsUtil.isEmpty(list)){
            return null;
        }
        // 本次评论
        PaasCommentEntityExt paasCommentEntityExt = list.get(0);
        // 评论
        String comment = paasCommentEntityExt.getContent();
        comment = formatComment(comment);
        // 跟进内容
        String memo = (String) data.get(CustomerCommunicateEnum.MEMO.getAttr());

        Map<String, Object> content = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        content.put("clientName",customerName);
        content.put("followContent",memo);
        content.put("comment",comment);

        // 卡片特殊属性json字符串
        CardPropertyPojo cardPropertyPojo = new CardPropertyPojo();
        // 互动卡片参数
        cardPropertyPojo.setAppId(cardDataEntity.getAppId());
        cardPropertyPojo.setMenuId(cardDataEntity.getMenuId());
        cardPropertyPojo.setFormId(cardDataEntity.getFormId());
        cardPropertyPojo.setSaasMark(cardDataEntity.getSaasMark());
        cardPropertyPojo.setBusinessType(cardDataEntity.getBusinessType());
        cardPropertyPojo.setDataId(dataId);
        cardPropertyPojo.setDistributorMark(BasicConstant.ZERO);
        cardPropertyPojo.setSubBusinessType(cardDataEntity.getBusinessType());
        cardPropertyPojo.setLinkDataId(data.getLong(CustomerCommunicateEnum.CUSTOMER_NAME.getAttr()));

        // 卡片解释
        CardTemplateExplainPojo cardTemplateExplainPojo = cardExplain.toJavaObject(CardTemplateExplainPojo.class);

        CardDataPojo cardDataPojo = formatCommunicateReplyCard(content, title, cardPropertyPojo, paasCommentEntityExt.getAddTime(), cardTemplateExplainPojo, userIds, cardDataEntity, paasCommentEntity, paasCommentEntityExt.getId());


        return bizManager.sendCard(accessToken, cardDataEntity, cardDataPojo);
    }

    public  String formatcontent(String c){
        StringBuilder content = new StringBuilder();
        if(c.contains("<span class=\"at-person\">")){
            String[] split = c.split("<span class=\"at-person\">");
            for (String s1 : split) {
                if ("".equals(s1)){
                    continue;
                }
                String[] split1 = s1.split("</span>");
                for (String s2 : split1) {
                    if (s2.endsWith("&nbsp;")){
                        String[] split2 = s2.split("&nbsp;");
                        content.append(split2[0]).append(" ");
                        continue;
                    }
                    if (s2.startsWith("&nbsp;")){
                        String[] split2 = s2.split("&nbsp;");
                        content.append(" ").append(split2[1]);
                        continue;
                    }
                    content.append(s2);
                }
            }
            return content.toString();
        } else if (c.contains("&nbsp;")){
            String[] split = c.split("&nbsp;");
            for (String s : split) {
                content.append(s).append(" ");
            }
            return content.toString();
        }
        return c;
    }

    /**
     * 评论解析
     * @param comment
     * @return
     */
    public String formatComment(String comment){
        String[] split = comment.split("<span class=\"at-person\">");
        StringBuilder content = new StringBuilder();
        for (String s1 : split) {
            if ("".equals(s1)){
                continue;
            }
            String[] split1 = s1.split("</span>");
            for (String s2 : split1) {
                if (s2.endsWith("&nbsp;")){
                    String[] split2 = s2.split("&nbsp;");
                    content.append(split2[0]).append(" ");
                    continue;
                }
                if (s2.startsWith("&nbsp;")){
                    String[] split2 = s2.split("&nbsp;");
                    content.append(" ").append(split2[1]);
                    continue;
                }
                content.append(s2);
            }
        }
        return content.toString();
    }

    public CardDataPojo formatCommunicateReplyCard(Map<String, Object> content, String title, CardPropertyPojo cardPropertyPojo, Long addTime,
                                                   CardTemplateExplainPojo cardTemplateExplainPojo, List<String> userIds, CoolAppCardDataEntity cardDataEntity, PaasCommentEntity paasCommentEntity, Long id){

        Map<String, String> cardData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        HashMap<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        String detailUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + cardDataEntity.getCorpid() + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ cardDataEntity.getOpenConversationId() + "&dd_nav_bgcolor=ffff943e#";
        detailUrl += String.format(CoolAppConstant.CUSTOMER_COMMUNICATE_DETAIL_PAGE_URL, paasCommentEntity.getRefId(),cardDataEntity.getAppId(), cardDataEntity.getMenuId(), cardDataEntity.getFormId(), cardDataEntity.getCardBizId());
        String pcDetailUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl + "&tabAttr=comment"+"&replyNameId=" + id);
        String mobileDetailUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl + "&tabAttr=comment"+"&replyNameId=" + id);
        JSONObject buttons = cardTemplateExplainPojo.getButtons();
        JSONObject reply = (JSONObject)buttons.get("reply");
        reply.put("pcUrl",pcDetailUrl);
        reply.put("mobileUrl",mobileDetailUrl);

        map.put("content",content);
        map.put("cardPropertyJson",cardPropertyPojo);
        cardData.put("title",title);
        cardData.put(COMPLEX_PARAM,JSON.toJSONString(map));

        String time = DateTimeUtil.getStringEpochSecond(addTime, DateTimeUtil.SDF);

        cardData.put("time",time);

        // 私有数据
        Map<String, Map<String, String>> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (String userId : userIds) {
            Map<String, Object> tempCardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, String> tempCardPrivateData1 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            tempCardPrivateData.put("buttons", cardTemplateExplainPojo.getButtons());
            tempCardPrivateData1.put(COMPLEX_PARAM, JSON.toJSONString(tempCardPrivateData));
            cardPrivateData.put(userId, tempCardPrivateData1);
        }
        return new CardDataPojo(userIds, cardData, cardPrivateData);
    }

    public void formatBusinessCardDataUpdate(String corpid,String accessToken, PaasFormDataEntityExt paasFormDataEntityExt, Long formId, Long dataId, boolean isAll, List<String> userIds, JSONObject cardExplain, CoolAppCardDataEntity cardDataEntity,CoolAppUpdateCardDTO coolAppUpdateCardDTO) throws XbbException {
        // 拼装卡片数据
        PaasFormEntityExt formEntityExt;
        try {
            formEntityExt = paasFormModel.getByKey(formId, corpid);
        } catch (Exception e) {
            formEntityExt = null;
        }
        if (Objects.isNull(formEntityExt)) {
            return;
        }
        PaasFormExplainEntity paasFormExplainEntity;
        try {
            paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
        } catch (XbbException e) {
            paasFormExplainEntity = null;
        }
        if (Objects.isNull(paasFormExplainEntity)) {
            return;
        }
        String explains = paasFormExplainEntity.getExplains();
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explains);


        List<SummaryDataPoJo> summaryList = new ArrayList<>();
//        try {
//            summaryList = paasFormHelp.getSummaryList(formEntityExt, explainMap, paasFormDataEntityExt);
//        } catch (XbbException e) {
//            summaryList = null;
//        }

//        if (Objects.isNull(summaryList)){
//            return;
//        }
        Integer businessType = cardDataEntity.getBusinessType();
        // 卡片解释
        CardTemplateExplainPojo cardTemplateExplainPojo = cardExplain.toJavaObject(CardTemplateExplainPojo.class);
        // 创建人
        String creatorId = paasFormDataEntityExt.getCreatorId();
        UserEntity creatorEntity = userModel.getByKey(creatorId, corpid);
        if (Objects.isNull(creatorEntity)){
            return;
        }

        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        // 获取数据摘要
        CardDataSummaryPojo cardDataSummaryPojo = new CardDataSummaryPojo();
        FormDataGetDTO formDataGetDTO = new FormDataGetDTO();
        BeanUtil.copyProperties(coolAppUpdateCardDTO,formDataGetDTO);
        if (!Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CUSTOMER_COMMUNICATE) && !Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.WORK_REPORT)) {
            cardDataSummaryPojo = formatBusinessCardDataSummary(corpid, businessType, explainMap, dataId, creatorId, summaryList, userIds, formDataGetDTO, paasFormDataEntityExt, paasFormExplainEntity, formEntityExt);
        }
        // 点赞数、评论数
        int commentCount = 0;
        int likeCount = 0;
        if (Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CUSTOMER_COMMUNICATE) || Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.WORK_REPORT)) {
            List<Long> dataIds = new ArrayList<>();
            dataIds.add(dataId);
            Map<Long, Integer> likeCountMap = likeService.getLikeCountMap(dataIds, corpid, BusinessCommentEnum.getByBusinessType(businessType).getCode());
//            Map<Long, Integer> commentCountMap = paasCommentModel.getCommnetCountMap(dataIds, corpid, BusinessCommentEnum.CUSTOMER_COMMUNICATE.getCode());
//            commentCount = commentCountMap.getOrDefault(dataId, BasicConstant.ZERO);
            likeCount = likeCountMap.getOrDefault(dataId, BasicConstant.ZERO);
        }

        // 卡片特殊属性json字符串
        CardPropertyPojo cardPropertyPojo = new CardPropertyPojo();
        // 互动卡片参数

        cardPropertyPojo.setAppId(cardDataEntity.getAppId());
        cardPropertyPojo.setMenuId(cardDataEntity.getMenuId());
        cardPropertyPojo.setFormId(cardDataEntity.getFormId());
        cardPropertyPojo.setSaasMark(cardDataEntity.getSaasMark());
        cardPropertyPojo.setBusinessType(cardDataEntity.getBusinessType());
        // 使用businessType
        cardPropertyPojo.setSubBusinessType(cardDataEntity.getBusinessType());
        cardPropertyPojo.setDataId(cardDataEntity.getDataId());

        JSONObject data = paasFormDataEntityExt.getData();
        if (xbbRefTypeEnum == XbbRefTypeEnum.CUSTOMER_COMMUNICATE) {
            // 获取必填字段
            List<String> requiredAttrList = new ArrayList<>();
            Set<Map.Entry<String, FieldAttrEntity>> entrySet = explainMap.entrySet();
            for (Map.Entry<String, FieldAttrEntity> entityEntry : entrySet) {
                FieldAttrEntity fieldAttrEntity = entityEntry.getValue();
                Integer required = fieldAttrEntity.getRequired();
                if (Objects.equals(required,BasicConstant.ONE)){
                    requiredAttrList.add(fieldAttrEntity.getAttr());
                }
            }
            // 若用户没有使用任何必填的系统字段
            if (requiredAttrList.size() < 1){
                requiredAttrList.add(CustomerCommunicateEnum.CUSTOMER_NAME.getAttr());
                requiredAttrList.add(CustomerCommunicateEnum.TYPE.getAttr());
                requiredAttrList.add(CustomerCommunicateEnum.COMMUNICATE_TIME.getAttr());
                requiredAttrList.add(CustomerCommunicateEnum.MEMO.getAttr());
            }
            cardDataSummaryPojo = getCustomerCommunicateContent(corpid, businessType, explainMap, dataId, creatorId, requiredAttrList, userIds, data, formDataGetDTO);
        }
        // 工作报告卡片内容
        if (Objects.equals(businessType,XbbRefTypeEnum.WORK_REPORT.getCode())){
            cardDataSummaryPojo = getWorkRepotrContent(corpid, businessType, explainMap, dataId, creatorId, userIds, data);
        }
        String openConversationId = coolAppUpdateCardDTO.getOpenConversationId();

        // 卡片跳转url
        String updateUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ openConversationId+ "&dd_nav_bgcolor=ffff943e#";
        String detailUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ openConversationId+ "&dd_nav_bgcolor=ffff943e#";
        String signInUrl = updateUrl;
        switch (xbbRefTypeEnum){
            case CUSTOMER_MANAGEMENT:
                updateUrl += String.format(CoolAppConstant.CUSTOMER_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.CUSTOMER_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
            case CONTRACT:
                updateUrl += String.format(CoolAppConstant.CONTRACT_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.CONTRACT_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                break;
            case CUSTOMER_COMMUNICATE:
                updateUrl += String.format(CoolAppConstant.CUSTOMER_COMMUNICATE_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.CUSTOMER_COMMUNICATE_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                break;
            case SALES_OPPORTUNITY:
                updateUrl += String.format(CoolAppConstant.SALES_OPPORTUNITY_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.SALES_OPPORTUNITY_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                break;
            case COMMUNICATE_PLAN:
                updateUrl += String.format(CoolAppConstant.COMMUNICATE_PLAN_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.COMMUNICATE_PLAN_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                signInUrl += String.format(CoolAppConstant.SIGNIN_PAGE_URL, cardDataEntity.getAppId(), cardDataEntity.getMenuId(), cardDataEntity.getCardBizId(), DateTimeUtil.getLong());
            case WORK_REPORT:
                int subBusinessType = 0;
                String o = data.getString(WorkReportDailyEnum.TYPE.getAttr());
                if (Objects.equals(o, "1")){
                    subBusinessType = XbbRefTypeEnum.WORKREPORT_DAILY.getCode();
                } else if (Objects.equals(o, "2")){
                    subBusinessType = XbbRefTypeEnum.WORKREPORT_WEEKLY.getCode();
                } else if (Objects.equals(o, "3")){
                    subBusinessType = XbbRefTypeEnum.WORKREPORT_MONTHLY.getCode();
                }
                detailUrl += String.format(CoolAppConstant.WORK_REPORT_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId(), subBusinessType);
                break;
            default:
                break;
        }

        CardDataPojo businessCardDataPojo = formatBusinessCard(cardDataSummaryPojo, cardTemplateExplainPojo, cardPropertyPojo, userIds, creatorEntity.getName(), businessType, formEntityExt.getName(),
                commentCount, likeCount, corpid, paasFormDataEntityExt, updateUrl, detailUrl, signInUrl, null);
        LOG.info("update-----------businessCardDataPojo:{}",JSON.toJSONString(businessCardDataPojo));
        bizManager.updateCard(accessToken, cardDataEntity.getCardBizId(), businessCardDataPojo);

    }

    public String formatBusinessCardData(String corpid,String accessToken, PaasFormDataEntityExt paasFormDataEntityExt, Long formId, Long dataId, boolean isAll, List<String> userIds, JSONObject cardExplain, CoolAppCardDataEntity cardDataEntity,CoolAppSendCardDTO coolAppSendCardDTO) throws XbbException {
        // 拼装卡片数据
        PaasFormEntityExt formEntityExt;
        try {
            formEntityExt = paasFormModel.getByKey(formId, corpid);
        } catch (Exception e) {
            formEntityExt = null;
        }
        if (Objects.isNull(formEntityExt)) {
            return null;
        }
        PaasFormExplainEntity paasFormExplainEntity;
        try {
            paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
        } catch (XbbException e) {
            paasFormExplainEntity = null;
        }
        if (Objects.isNull(paasFormExplainEntity)) {
            return null;
        }
        String explains = paasFormExplainEntity.getExplains();
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explains);


        List<SummaryDataPoJo> summaryList = new ArrayList<>();
//        try {
//            summaryList = paasFormHelp.getSummaryList(formEntityExt, explainMap, paasFormDataEntityExt);
//        } catch (XbbException e) {
//            summaryList = null;
//        }


        Integer businessType = coolAppSendCardDTO.getBusinessType();
        // 卡片解释
        CardTemplateExplainPojo cardTemplateExplainPojo = cardExplain.toJavaObject(CardTemplateExplainPojo.class);
        // 创建人
        String creatorId = paasFormDataEntityExt.getCreatorId();
        UserEntity creatorEntity = userModel.getByKey(creatorId, corpid);
        if (Objects.isNull(creatorEntity)) {
            return null;
        }

        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        FormDataGetDTO formDataGetDTO = new FormDataGetDTO();
        BeanUtil.copyProperties(coolAppSendCardDTO,formDataGetDTO);
        // 获取数据摘要
        CardDataSummaryPojo cardDataSummaryPojo = new CardDataSummaryPojo();
        // 非跟进记录和工作报告
        if (!Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CUSTOMER_COMMUNICATE) && !Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.WORK_REPORT)) {
            cardDataSummaryPojo = formatBusinessCardDataSummary(corpid, businessType, explainMap, dataId, creatorId, summaryList, userIds, formDataGetDTO, paasFormDataEntityExt, paasFormExplainEntity, formEntityExt);
        }
        // 点赞数、评论数
        int commentCount = 0;
        int likeCount = 0;
        if (Objects.equals(businessType,XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode()) || Objects.equals(businessType,XbbRefTypeEnum.WORK_REPORT.getCode())) {
            List<Long> dataIds = new ArrayList<>();
            dataIds.add(dataId);
            Map<Long, Integer> likeCountMap = likeService.getLikeCountMap(dataIds, corpid, BusinessCommentEnum.getByBusinessType(businessType).getCode());
//            Map<Long, Integer> commentCountMap = paasCommentModel.getCommnetCountMap(dataIds, corpid, BusinessCommentEnum.CUSTOMER_COMMUNICATE.getCode());
//            commentCount = commentCountMap.getOrDefault(dataId, BasicConstant.ZERO);
            likeCount = likeCountMap.getOrDefault(dataId, BasicConstant.ZERO);
        }

        // 卡片特殊属性json字符串
        CardPropertyPojo cardPropertyPojo = new CardPropertyPojo();
        // 互动卡片参数

        cardPropertyPojo.setAppId(cardDataEntity.getAppId());
        cardPropertyPojo.setMenuId(cardDataEntity.getMenuId());
        cardPropertyPojo.setFormId(cardDataEntity.getFormId());
        cardPropertyPojo.setSaasMark(cardDataEntity.getSaasMark());
        cardPropertyPojo.setBusinessType(cardDataEntity.getBusinessType());
        // 使用businessType
        cardPropertyPojo.setSubBusinessType(cardDataEntity.getBusinessType());
        cardPropertyPojo.setDataId(cardDataEntity.getDataId());

        JSONObject data = paasFormDataEntityExt.getData();
        if (Objects.equals(businessType,XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode())){
            // 获取必填字段
            List<String> requiredAttrList = new ArrayList<>();
            Set<Map.Entry<String, FieldAttrEntity>> entrySet = explainMap.entrySet();
            for (Map.Entry<String, FieldAttrEntity> entityEntry : entrySet) {
                FieldAttrEntity fieldAttrEntity = entityEntry.getValue();
                Integer required = fieldAttrEntity.getRequired();
                if (Objects.equals(required,BasicConstant.ONE)){
                    requiredAttrList.add(fieldAttrEntity.getAttr());
                }
            }
            // 若用户没有使用任何必填的系统字段
            if (requiredAttrList.size() < 1){
                requiredAttrList.add(CustomerCommunicateEnum.CUSTOMER_NAME.getAttr());
                requiredAttrList.add(CustomerCommunicateEnum.TYPE.getAttr());
                requiredAttrList.add(CustomerCommunicateEnum.COMMUNICATE_TIME.getAttr());
                requiredAttrList.add(CustomerCommunicateEnum.MEMO.getAttr());
            }
            cardDataSummaryPojo = getCustomerCommunicateContent(corpid, businessType, explainMap, dataId, creatorId, requiredAttrList, userIds, data, formDataGetDTO);
        }
        // 工作报告卡片内容
        if (Objects.equals(businessType,XbbRefTypeEnum.WORK_REPORT.getCode())){
            cardDataSummaryPojo = getWorkRepotrContent(corpid, businessType, explainMap, dataId, creatorId, userIds, data);
        }
        String openConversationId = cardDataEntity.getOpenConversationId();

        // 卡片跳转url
        String updateUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ openConversationId+ "&dd_nav_bgcolor=ffff943e#";
        String detailUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ openConversationId+ "&dd_nav_bgcolor=ffff943e#";
        String signInUrl = detailUrl;
        switch (xbbRefTypeEnum){
            case CUSTOMER_MANAGEMENT:
                updateUrl += String.format(CoolAppConstant.CUSTOMER_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.CUSTOMER_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                break;
            case CONTRACT:
                updateUrl += String.format(CoolAppConstant.CONTRACT_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.CONTRACT_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                break;
            case CUSTOMER_COMMUNICATE:
                updateUrl += String.format(CoolAppConstant.CUSTOMER_COMMUNICATE_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.CUSTOMER_COMMUNICATE_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                break;
            case SALES_OPPORTUNITY:
                updateUrl += String.format(CoolAppConstant.SALES_OPPORTUNITY_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.SALES_OPPORTUNITY_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                break;
            case COMMUNICATE_PLAN:
                updateUrl += String.format(CoolAppConstant.COMMUNICATE_PLAN_UPDATE_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                detailUrl += String.format(CoolAppConstant.COMMUNICATE_PLAN_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                signInUrl += String.format(CoolAppConstant.SIGNIN_PAGE_URL, cardDataEntity.getAppId(), cardDataEntity.getMenuId(), cardDataEntity.getCardBizId(), DateTimeUtil.getLong());
                break;
            case WORK_REPORT:
                int subBusinessType = 0;
                String o = data.getString(WorkReportDailyEnum.TYPE.getAttr());
                if (Objects.equals(o, "1")){
                    subBusinessType = XbbRefTypeEnum.WORKREPORT_DAILY.getCode();
                } else if (Objects.equals(o, "2")){
                    subBusinessType = XbbRefTypeEnum.WORKREPORT_WEEKLY.getCode();
                } else if (Objects.equals(o, "3")){
                    subBusinessType = XbbRefTypeEnum.WORKREPORT_MONTHLY.getCode();
                }
                detailUrl += String.format(CoolAppConstant.WORK_REPORT_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId(), subBusinessType);
                break;
            default:
                break;
        }

        CardDataPojo businessCardDataPojo = formatBusinessCard(cardDataSummaryPojo, cardTemplateExplainPojo, cardPropertyPojo, userIds, coolAppSendCardDTO.getLoginUserName(), businessType, formEntityExt.getName(),
                commentCount, likeCount, corpid, paasFormDataEntityExt, updateUrl, detailUrl, signInUrl, coolAppSendCardDTO.getIsUpdate());
        return bizManager.sendCard(accessToken, cardDataEntity, businessCardDataPojo);

    }

    public CardDataSummaryPojo getCustomerCommunicateContent(String corpid, Integer businessType, Map<String, FieldAttrEntity> explainMap, Long dataId, String creatorId, List<String> requiredAttrList,
                                                                                List<String> receiverUserIdList, JSONObject data, FormDataGetDTO formDataGetDTO) throws XbbException {
        if (CollectionsUtil.isEmpty(requiredAttrList)) {
            return null;
        }
        if (CollectionsUtil.isEmpty(receiverUserIdList)) {
            return null;
        }


        List<Long> dataIdIn = new ArrayList<>();
        dataIdIn.add(dataId);
        //协同团队
        Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionsUtil.isNotEmpty(dataIdIn)){
            userTeamHelp.setUserIdMap(dataIdIn, corpid, businessType, false, mainUserMap, coUserMap);
        }

        // 获取发送人列表
        List<UserEntity> userList = userModel.getByUserId(receiverUserIdList, corpid);

        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();

        handlerExplainDTO.setOwnerId(mainUserMap.get(dataId));
        handlerExplainDTO.setCoUserId(coUserMap.get(dataId));
        handlerExplainDTO.setCreatorId(creatorId);

        TransmittableThreadLocalUtil.setValue(formDataGetDTO.getSaasMark(), formDataGetDTO.getBusinessType(), formDataGetDTO.getMenuId(), DistributorMarkEnum.OTHER.getCode());
        FormDataGetVO formDataGetVO = paasFormDataService.get(formDataGetDTO);
        JSONObject voData = formDataGetVO.getData();
        // 接收人是否超过20人
        List<String> commonAttrList = new ArrayList<>();
        JSONArray cardData = getCommonRequiredList(requiredAttrList, userList, explainMap, handlerExplainDTO, commonAttrList, voData);

        Map<String, JSONArray> cardPrivateData = null;

        if (userList.size() <= BasicConstant.TWENTY) {
            commonAttrList.clear();
            cardPrivateData = getPrivateRequiredList(requiredAttrList, userList, explainMap, handlerExplainDTO, commonAttrList, voData, data);
        }
        CardDataSummaryPojo cardDataPojo = new CardDataSummaryPojo();
        if (CollectionsUtil.isNotEmpty(cardData)) {
            cardDataPojo.setCardData(cardData);
        }
        if (Objects.nonNull(cardPrivateData)) {
            cardDataPojo.setCardPrivateData(cardPrivateData);
        }
        return cardDataPojo;
    }

    public CardDataSummaryPojo getWorkRepotrContent(String corpid, Integer businessType, Map<String, FieldAttrEntity> explainMap, Long dataId, String creatorId,
                                                             List<String> receiverUserIdList, JSONObject data) throws XbbException {
        Map<String, JSONArray> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> dataIdIn = new ArrayList<>();
        dataIdIn.add(dataId);
        //协同团队
        Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionsUtil.isNotEmpty(dataIdIn)) {
            userTeamHelp.setUserIdMap(dataIdIn, corpid, businessType, false, mainUserMap, coUserMap);
        }

        // 获取发送人列表
        List<UserEntity> userList = userModel.getByUserId(receiverUserIdList, corpid);

        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();

        handlerExplainDTO.setOwnerId(mainUserMap.get(dataId));
        handlerExplainDTO.setCoUserId(coUserMap.get(dataId));
        handlerExplainDTO.setCreatorId(creatorId);

        ArrayList<String> contentAttrList = new ArrayList<>();
        contentAttrList.add(WorkReportDailyEnum.TYPE.getAttr());
        contentAttrList.add(WorkReportDailyEnum.REPORT_DATE.getAttr());

        for (String attr : contentAttrList) {
            for (UserEntity userEntity : userList) {
                UserVO userVO = new UserVO();
                BeanUtil.copyProperties(userEntity, userVO);
                handlerExplainDTO.setLoginUser(userVO);
                handlerExplainDTO.setUserId(userVO.getUserId());
                boolean canSee = commonHelp.attrCanSee(attr, explainMap, handlerExplainDTO);
                String value = "";
                if (Objects.equals(attr, WorkReportDailyEnum.TYPE.getAttr())){
                    String o = data.getString(attr);
                    if (Objects.equals(o, "1")){
                        value = "日报";
                    } else if (Objects.equals(o, "2")){
                        value = "周报";
                    } else if (Objects.equals(o, "3")){
                        value = "月报";
                    }
                    value = canSee ? value : "--";
                } else {
                    Long time = FastJsonHelper.getLongOrDefaultFromFormData(data, attr, DateTimeUtil.getInt());
                    String dataTime = DateTimeUtil.getStringEpochSecond(time, DateTimeUtil.SDFDate);
                    value = canSee ? dataTime : "--";
                }
                ItemDataPoJo itemDataPoJo = new ItemDataPoJo();
                FieldAttrEntity fieldAttrEntity = explainMap.get(attr);
                itemDataPoJo.setText(fieldAttrEntity.getAttrName());
                itemDataPoJo.setValue(value);

                JSONArray itemDataList = cardPrivateData.getOrDefault(userEntity.getUserId(), new JSONArray());
                itemDataList.add(itemDataPoJo);
                cardPrivateData.put(userEntity.getUserId(), JSONArray.parseArray(itemDataList.toString()));
            }
        }
        CardDataSummaryPojo cardDataPojo = new CardDataSummaryPojo();
        cardDataPojo.setCardData(new JSONArray());
        cardDataPojo.setCardPrivateData(cardPrivateData);
        return cardDataPojo;
    }

    public CardDataPojo formatBusinessCard(CardDataSummaryPojo cardDataSummaryPojo, CardTemplateExplainPojo cardTemplateExplainPojo,CardPropertyPojo cardPropertyPojo,
                                                   List<String> userIds, String creatorName, Integer businessType, String formName, int commentCount, int likeCount, String corpid,
                                                   PaasFormDataEntityExt paasFormDataEntityExt, String updateUrl, String detailUrl, String signInUrl, Integer isUpdate) throws XbbException {

        Map<String, String> cardData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        HashMap<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 标题
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        // todo 国际化
        String title = "";
        boolean isSimple = userIds.size() > CoolAppConstant.SIMPLE_CARD_USER_NUM;
        // 极简卡片只有一个标题和一个查看详情按钮
        if (isSimple){
            String operate = "";
            if (Objects.nonNull(isUpdate) && Objects.equals(isUpdate,BasicConstant.ONE)){
                operate = "更新";
                if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.COMMUNICATE_PLAN)){
                    operate = "延期";
                }
            } else {
                operate = "新增";
            }
            String pcDetailUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl);
            String mobileDetailUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl);
            // 按钮添加url
            JSONObject buttons = cardTemplateExplainPojo.getButtons();
            JSONObject detail = (JSONObject)buttons.get("detail");
            detail.put("pcUrl",pcDetailUrl);
            detail.put("mobileUrl",mobileDetailUrl);
//            map.put("buttons", detail);
//            // 对象 数组等复杂数据固定格式
//            cardData.put(COMPLEX_PARAM,JSON.toJSONString(map));
            JSONObject data = paasFormDataEntityExt.getData();
            String content = "";
            switch (xbbRefTypeEnum){
                case CUSTOMER_MANAGEMENT:
                    content =  "\"" + creatorName + "\"" + operate + "了客户"+ "\"" + data.getString(CustomerManagementEnum.NAME.getAttr()) + "\"";
                    title = operate + "客户";
                    break;
                case CUSTOMER_COMMUNICATE:
                    content = "\"" + creatorName + "\"" + operate + "了跟进记录";
                    title = operate + "跟进记录";
                    break;
                case CONTRACT:
                    content = "\"" + creatorName + "\"" + operate + "了合同" + "\"" + data.getString(ContractEnum.NAME.getAttr()) + "\"";
                    title = operate + "合同";
                    break;
                case SALES_OPPORTUNITY:
                    content = "\"" + creatorName + "\"" + operate + "了机会" + "\"" + data.getString(SalesOpportunityEnum.NAME.getAttr()) + "\"";
                    title = operate + "机会";
                    break;
                case COMMUNICATE_PLAN:
                    content = "\"" + creatorName + "\"" + operate + "了访客计划" + "\"" + data.getString(CommunicatePlanEnum.NAME.getAttr()) + "\"";
                    title = operate + "访客计划";
                    break;
                case WORK_REPORT:
                    String type = "";
                    String o = data.getString(WorkReportDailyEnum.TYPE.getAttr());
                    if (Objects.equals(o, "1")){
                        type = "日报";
                    } else if (Objects.equals(o, "2")){
                        type = "周报";
                    } else if (Objects.equals(o, "3")){
                        type = "月报";
                    }
                    Long time = FastJsonHelper.getLongOrDefaultFromFormData(data, WorkReportDailyEnum.REPORT_DATE.getAttr(), DateTimeUtil.getInt());
                    String dataTime = DateTimeUtil.getStringEpochSecond(time, DateTimeUtil.SDFDate);
                    content = "\"" + creatorName + "\"" + operate + "了工作报告 "+ type + "(\"" + dataTime + "\")";
                    title = operate + "工作报告";
                    break;
                default:
                    break;
            }
            cardData.put("title", title);
            cardData.put("simpleContent",content);
            // 按钮放私有数据里面
            Map<String, Map<String, String>> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (String userId : userIds) {
                Map<String, Object> tempCardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String, String> tempCardPrivateData1 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("detail",detail);
                tempCardPrivateData.put("buttons", jsonObject);
                tempCardPrivateData1.put(COMPLEX_PARAM, JSON.toJSONString(tempCardPrivateData));
                cardPrivateData.put(userId,tempCardPrivateData1);
            }
            return new CardDataPojo(userIds, cardData, cardPrivateData);
        }

        if (Objects.nonNull(isUpdate) && Objects.equals(isUpdate,BasicConstant.ONE)){
            title = creatorName + "更新了" + xbbRefTypeEnum.getName();
        } else {
            title = creatorName + "创建的" + xbbRefTypeEnum.getName();
        }
        cardData.put("title", title);
        // 数据摘要
        if (Objects.nonNull(cardDataSummaryPojo) && Objects.nonNull(cardDataSummaryPojo.getCardData())) {
            map.put("content",cardDataSummaryPojo.getCardData());
        }
        // 卡片特殊属性json字符串
        map.put("cardPropertyJson", cardPropertyPojo);
        // 点赞数、评论数
        if (xbbRefTypeEnum != XbbRefTypeEnum.CUSTOMER_COMMUNICATE && xbbRefTypeEnum != XbbRefTypeEnum.WORK_REPORT) {
            cardTemplateExplainPojo.getButtons().remove("like");
            cardTemplateExplainPojo.getButtons().remove("comment");
        }
        if(xbbRefTypeEnum != XbbRefTypeEnum.CUSTOMER_MANAGEMENT && xbbRefTypeEnum != XbbRefTypeEnum.SALES_OPPORTUNITY &&
                xbbRefTypeEnum != XbbRefTypeEnum.COMMUNICATE_PLAN){
            cardTemplateExplainPojo.getButtons().remove("writeFollow");
        }
        if (xbbRefTypeEnum != XbbRefTypeEnum.COMMUNICATE_PLAN){
            cardTemplateExplainPojo.getButtons().remove("signIn");
        }
        if (xbbRefTypeEnum != XbbRefTypeEnum.SALES_OPPORTUNITY){
            cardTemplateExplainPojo.getButtons().remove("signContract");
        }
        // 工作报告去除编辑按钮
        if (xbbRefTypeEnum == XbbRefTypeEnum.WORK_REPORT){
            cardTemplateExplainPojo.getButtons().remove("edit");
        }
        // 对象 数组等复杂数据固定格式
        cardData.put(COMPLEX_PARAM,JSON.toJSONString(map));

        // 按钮url
        // 访客计划更改计划按钮标识
        if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.COMMUNICATE_PLAN)){
            updateUrl = updateUrl + "&coolAppOperate=" + CoolAppButtonOperateEnum.DEFERRED_PLAN.getAlias();
        }
        String pcUpdateUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(updateUrl);
        String mobileUpdateUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(updateUrl);
        String pcDetailUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl);
        String mobileDetailUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl);
        String pcWriteCommunicateUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl + "&coolAppOperate=" + CoolAppButtonOperateEnum.FOLLOW_UP.getAlias());
        String mobileWriteCommunicateUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl + "&coolAppOperate="  + CoolAppButtonOperateEnum.FOLLOW_UP.getAlias());
        // 私有数据
        Map<String, JSONArray> cardPrivateData1 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (Objects.nonNull(cardDataSummaryPojo) && Objects.nonNull(cardDataSummaryPojo.getCardPrivateData())) {
            cardPrivateData1 = cardDataSummaryPojo.getCardPrivateData();
        }

        // 按钮添加url
        JSONObject buttons = cardTemplateExplainPojo.getButtons();
        // 工作报告没有编辑按钮
        if (xbbRefTypeEnum != XbbRefTypeEnum.WORK_REPORT){
            JSONObject edit = (JSONObject)buttons.get("edit");
            edit.put("pcUrl",pcUpdateUrl);
            edit.put("mobileUrl",mobileUpdateUrl);
        }
        JSONObject detail = (JSONObject)buttons.get("detail");
        detail.put("pcUrl",pcDetailUrl);
        detail.put("mobileUrl",mobileDetailUrl);
        // 评论按钮url
        if(Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CUSTOMER_COMMUNICATE) || Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.WORK_REPORT)){
            String pcDetailUrl1 = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl + "&coolAppOperate=" + CoolAppButtonOperateEnum.OPEN_COMMENT.getAlias());
            String mobileDetailUrl1 = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl + "&coolAppOperate=" + CoolAppButtonOperateEnum.OPEN_COMMENT.getAlias());
            JSONObject comment = (JSONObject)buttons.get("comment");
            comment.put("pcUrl",pcDetailUrl1);
            comment.put("mobileUrl",mobileDetailUrl1);
        }
        // 写跟进按钮url
        if (Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CUSTOMER_MANAGEMENT) || Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.SALES_OPPORTUNITY) ||
                Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.COMMUNICATE_PLAN)){
            JSONObject writeFollow = buttons.getJSONObject("writeFollow");
            writeFollow.put("pcUrl",pcWriteCommunicateUrl);
            writeFollow.put("mobileUrl",mobileWriteCommunicateUrl);
        }
        // 签订合同按钮url
        if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.SALES_OPPORTUNITY)){
            String pcDetailUrl1 = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl +"&coolAppOperate=" + CoolAppButtonOperateEnum.SIGN_CONTRACT.getAlias());
            String mobileDetailUrl1 = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl +"&coolAppOperate="  + CoolAppButtonOperateEnum.SIGN_CONTRACT.getAlias());
            JSONObject signContract = buttons.getJSONObject("signContract");
            signContract.put("pcUrl",pcDetailUrl1);
            signContract.put("mobileUrl",mobileDetailUrl1);
        }
        // 签到按钮url
        if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.COMMUNICATE_PLAN)){
            String mobileSignInUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(signInUrl);
            String pcSignInUrl =  CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(signInUrl);
            JSONObject signIn = (JSONObject) buttons.get("signIn");
            signIn.put("pcUrl",pcSignInUrl);
            signIn.put("mobileUrl",mobileSignInUrl);
            JSONObject edit1 = (JSONObject) buttons.get("edit");
            edit1.put("name","更改计划");
        }
        HashMap<String, String> likeMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (Objects.equals(businessType,XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode()) || Objects.equals(businessType,XbbRefTypeEnum.WORK_REPORT.getCode())) {
            // 是否点赞判断
            Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid",corpid);
            param.put("type",BusinessCommentEnum.getByBusinessType(businessType).getCode());
            param.put("appId",paasFormDataEntityExt.getAppId());
            param.put("refId",paasFormDataEntityExt.getId());
            param.put("userIdIn",userIds);
            param.put("del",0);
            List<LikeEntity> likeEntities = likeModel.findEntitys(param);
            for (String userId : userIds) {
                likeMap.put(userId,"false");
            }
            for (LikeEntity likeEntity : likeEntities) {
                if (userIds.contains(likeEntity.getUserId())){
                    likeMap.put(likeEntity.getUserId(),"true");
                }
            }
        }
        Map<String, Map<String, String>> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (String userId : userIds) {
            JSONArray contentArray = null;
            if (cardPrivateData1.containsKey(userId)) {
                contentArray = cardPrivateData1.get(userId);
            }
            Map<String, Object> tempCardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, String> tempCardPrivateData1 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (CollectionsUtil.isNotEmpty(contentArray)) {
                tempCardPrivateData.put("content", contentArray);
            }

            // 按钮根据权限过滤
//            UserVO userVO = getUserInfo(corpid, userId);
//            FormDataGetVO formDataGetVO = new FormDataGetVO();
//            formDataGetVO.setDistributorMark(0);
//            mobileDetailService.handelMobileWorkFlow(userVO, XbbRefTypeEnum.transferBusinessType4Distributor(businessType,0), formDataGetVO, paasFormDataEntityExt);
//            boolean isEdit = false;
//            boolean isWriteComminicate = false;
//            List<TopPermissionsPoJo> topPermissions = formDataGetVO.getTopPermissions();
//            for (TopPermissionsPoJo topPermission : topPermissions) {
//                if(Objects.equals(topPermission.getAttr(), OperateTypeEnum.EDIT.getAlias())){
//                    isEdit = true;
//                    break;
//                }
//            }
//            if (userVO.getPermSet().contains(ProPermissionAliasEnum.CUSTOMER_COMMUNICATE_ADD.getAlias())){
//                isWriteComminicate = true;
//            }
            JSONObject tempButtons = (JSONObject) cardTemplateExplainPojo.getButtons().clone();
//            if (!isEdit){
//                tempButtons.remove("edit");
//            }
            if (!Objects.equals(XbbRefTypeEnum.CUSTOMER_MANAGEMENT,xbbRefTypeEnum) && !Objects.equals(XbbRefTypeEnum.SALES_OPPORTUNITY,xbbRefTypeEnum)
                    && !Objects.equals(XbbRefTypeEnum.COMMUNICATE_PLAN,xbbRefTypeEnum)){
                tempButtons.remove("writeFollow");
            }
            tempCardPrivateData.put("buttons", tempButtons);
            tempCardPrivateData1.put(COMPLEX_PARAM, JSON.toJSONString(tempCardPrivateData));
            if (Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.CUSTOMER_COMMUNICATE) || Objects.equals(xbbRefTypeEnum,XbbRefTypeEnum.WORK_REPORT)) {
//                tempCardPrivateData1.put("commentNum", commentCount + "");
                tempCardPrivateData1.put("likeNum", likeCount + "");
                tempCardPrivateData1.put("ifLike", likeMap.get(userId));
            }
            cardPrivateData.put(userId, tempCardPrivateData1);
        }

        return new CardDataPojo(userIds, cardData, cardPrivateData);
    }

    public UserVO getUserInfo(String corpid, String userId){

        UserVO userVO = null;
        try {
            UserEntity user = userModel.getByKey(userId, corpid);

            if(user == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.USER_NOT_EXIST);
            }
            //用户信息
            userVO = new UserVO();
            BeanUtil.copyProperties(user, userVO);
            //用户复杂数据
            userModel.assembleUserVO(userVO, true);
        } catch (XbbException e) {
            LOG.error("com.xbongbong.coolapp.service.impl.CoolAppCardServiceImpl.getUserInfo is error", e);
        } catch (Exception e) {
            LOG.error("com.xbongbong.coolapp.service.impl.CoolAppCardServiceImpl.getUserInfo is error", e);
        }
        return userVO;
    }

    /**
     * 新建业务的卡片数据摘要
     *
     * @param explainMap
     * @param dataId
     * @param
     * @param summaryList
     * @param receiverUserIdList
     * @return
     */
    public CardDataSummaryPojo formatBusinessCardDataSummary(String corpid, Integer businessType, Map<String, FieldAttrEntity> explainMap, Long dataId, String creatorId,
                                                             List<SummaryDataPoJo> summaryList, List<String> receiverUserIdList, FormDataGetDTO formDataGetDTO,
                                                             PaasFormDataEntityExt paasFormDataEntityExt, PaasFormExplainEntity paasFormExplainEntity, PaasFormEntityExt paasFormEntityExt) throws XbbException {

//        if (CollectionsUtil.isEmpty(summaryList)) {
//            return null;
//        }
        if (CollectionsUtil.isEmpty(receiverUserIdList)) {
            return null;
        }


        List<Long> dataIdIn = new ArrayList<>();
        dataIdIn.add(dataId);
        //协同团队
        Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionsUtil.isNotEmpty(dataIdIn)){
            userTeamHelp.setUserIdMap(dataIdIn, corpid, businessType, false, mainUserMap, coUserMap);
        }

        // 获取发送人列表
        List<UserEntity> userList = userModel.getByUserId(receiverUserIdList, corpid);

        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();

        handlerExplainDTO.setOwnerId(mainUserMap.get(dataId));
        handlerExplainDTO.setCoUserId(coUserMap.get(dataId));
        handlerExplainDTO.setCreatorId(creatorId);

//        TransmittableThreadLocalUtil.setValue(formDataGetDTO.getSaasMark(), formDataGetDTO.getBusinessType(), formDataGetDTO.getMenuId(), DistributorMarkEnum.OTHER.getCode());
//        FormDataGetVO formDataGetVO = paasFormDataService.get(formDataGetDTO);

        // 接收人是否超过20人
        List<String> commonAttrList = new ArrayList<>();
//        JSONArray cardData = getCommonSummaryList(summaryList, userList, explainMap, handlerExplainDTO, commonAttrList);
        JSONArray cardData = new JSONArray();

        Map<String, JSONArray> cardPrivateData = null;

        List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
        BeanUtil.copyProperties(formDataGetDTO, handlerExplainDTO, false);
        handlerExplainDTO.setCreatorId(creatorId);
        // ---- 获取用户和部门容器start
        UserAndDepartmentGetDTO userAndDepartmentGetDTO = new UserAndDepartmentGetDTO();
        BeanUtil.copyProperties(formDataGetDTO, userAndDepartmentGetDTO);
        userAndDepartmentGetDTO.setExplainList(explainList);

        Map<String, UserEntity> userMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, DepartmentEntity> departmentMap = commonHelp.getDepMap(userAndDepartmentGetDTO);
        handlerExplainDTO.setExplainList(explainList);
        // 获取协同人和负责人
        JSONObject ownerAndCoUser = paasFormHelp.getOwnerIdAndCoUserId(handlerExplainDTO, 1, businessType, businessType, paasFormDataEntityExt, userMap);

        JSONObject data = paasFormDataEntityExt.getData();
        data.put(FieldTypeEnum.ADDTIME.getAlias(), paasFormDataEntityExt.getAddTime());
        data.put(FieldTypeEnum.UPDATETIME.getAlias(), paasFormDataEntityExt.getUpdateTime());
        data.put(FieldTypeEnum.SERIALNO.getAlias(), paasFormDataEntityExt.getSerialNo());
        data.put(FieldTypeEnum.CREATORID.getAlias(), paasFormDataEntityExt.getCreatorId());
        data.put(FieldTypeEnum.DEPARTMENTID.getAlias(), paasFormDataEntityExt.getDepartmentId());
        data.putAll(ownerAndCoUser);
        ParseSingleRowDataDTO parseSingleRowDataDTO = new ParseSingleRowDataDTO();
        BeanUtil.copyProperties(formDataGetDTO, parseSingleRowDataDTO);
        parseSingleRowDataDTO.setDataJsonObject(data);
        parseSingleRowDataDTO.setExplainMap(explainMap);
        parseSingleRowDataDTO.setUserMap(userMap);
        parseSingleRowDataDTO.setDepartmentMap(departmentMap);
        // 解析数据
        ParseSingleRowDataVO parseSingleRowDataVO = formDataGetAnalysisDataHelp.parseSingleRowData(parseSingleRowDataDTO);
        if ( Objects.isNull(parseSingleRowDataVO) ) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PARSE_SINGLE_ROW_DATA_FAILED);
        }
        data = parseSingleRowDataVO.getResult();
        // 解析访客计划执行人
        if (Objects.equals(businessType, XbbRefTypeEnum.COMMUNICATE_PLAN.getCode())){
            Map<String,Object> parme = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            parme.put("corpid",corpid);
            parme.put("dataIdIn",dataIdIn);
            List<CommunicatePlanUserEntity> planUserModelList = communicatePlanUserModel.findEntitys(parme);
            Map<Long, String> planUserModelMap = planUserModelList.stream().collect(Collectors.toMap(CommunicatePlanUserEntity::getDataId,
                    CommunicatePlanUserEntity::getUserName,
                    (value1, value2) -> value1 + StringConstant.COMMA + value2));
            for (Map.Entry<Long, String> entry : planUserModelMap.entrySet()) {
                List<String> list = new ArrayList<>();
                list.add(entry.getValue());
                data.put(CommunicatePlanEnum.EXECUTOR.getAttr(),list);
            }

        }
        // 解析摘要
        List<SummaryDataPoJo> summaryList1 = ExplainUtil.getSpecialSummaryList(paasFormEntityExt.getSummaryList(), data, explainMap, paasFormDataEntityExt);
        if (userList.size() <= BasicConstant.TWENTY) {
            commonAttrList.clear();
            cardPrivateData = getPrivateSummaryList(summaryList1, userList, explainMap, handlerExplainDTO, commonAttrList);
        }
        CardDataSummaryPojo cardDataPojo = new CardDataSummaryPojo();
        if (Objects.nonNull(cardData)) {
            cardDataPojo.setCardData(cardData);
        }
        if (Objects.nonNull(cardPrivateData)) {
            cardDataPojo.setCardPrivateData(cardPrivateData);
        }
        return cardDataPojo;
    }

    public String formatStageCardData(String corpid,String accessToken, PaasFormDataEntityExt paasFormDataEntityExt, Long formId, Long dataId, boolean isAll, List<String> userIds, JSONObject cardExplain, CoolAppCardDataEntity cardDataEntity, CoolAppSendCardDTO coolAppSendCardDTO) throws XbbException {
//        CustomerEntityExt customerEntityExt = customerModel.getByKey(dataId, corpid);
        paasFormDataEntityExt = saasGetHelp.getFormData(dataId, corpid, coolAppSendCardDTO.getBusinessType());
        if (Objects.isNull(paasFormDataEntityExt)){
            return null;
        }
        Integer businessType = coolAppSendCardDTO.getBusinessType();
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        CardDataPojo cardDataPojo;
        // 卡片解释
        CardTemplateExplainPojo cardTemplateExplainPojo = cardExplain.toJavaObject(CardTemplateExplainPojo.class);
        String openConversationId = coolAppSendCardDTO.getOpenConversationId();
        String detailUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID +"&openConversationId="+ openConversationId+ "&dd_nav_bgcolor=ffff943e#";
        switch (xbbRefTypeEnum){
            case CUSTOMER_MANAGEMENT:
                detailUrl += String.format(CoolAppConstant.CUSTOMER_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                break;
            case SALES_OPPORTUNITY:
                detailUrl += String.format(CoolAppConstant.SALES_OPPORTUNITY_DETAIL_PAGE_URL, dataId,cardDataEntity.getAppId(), cardDataEntity.getMenuId(), formId, cardDataEntity.getCardBizId());
                break;
            default:
                break;
        }
            StageGetDTO stageGetDTO = new StageGetDTO();
            stageGetDTO.setBusinessType(xbbRefTypeEnum.getCode());
            BeanUtil.copyProperties(coolAppSendCardDTO,stageGetDTO);
            stageGetDTO.setDataId(dataId);
            stageGetDTO.setFormId(paasFormDataEntityExt.getFormId());
            stageGetDTO.setBusinessType(xbbRefTypeEnum.getCode());
            Integer subBusinessType = null;
            if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.CUSTOMER_MANAGEMENT)){
                subBusinessType = XbbRefTypeEnum.CUSTOMER.getCode();
            } else if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.SALES_OPPORTUNITY)){
                subBusinessType = XbbRefTypeEnum.ALL_OPPORTUNITY.getCode();
            }
            stageGetDTO.setSubBusinessType(subBusinessType);
            stageGetDTO.setSaasMark(BasicConstant.ONE);
            stageGetDTO.setCorpid(corpid);
            stageGetDTO.setUserId(coolAppSendCardDTO.getUserId());
            stageGetDTO.setDistributorMark(BasicConstant.ZERO);
            stageGetDTO.setPlatform(PlatFormEnum.DINGTALK.getValue());
            StageGetVO stageGetVO = detailStageService.stageGet(stageGetDTO);
            if (Objects.isNull(stageGetVO)){
                return null;
            }
            List<StageGetAllListPojo> stageList = stageGetVO.getStageList();
            StageGetAllListPojo stageGetAllListPojo = new StageGetAllListPojo();
            Long stageLogId = 0L;
            Long stageId = 0L;
            for (StageGetAllListPojo stageGetAllList : stageList) {
                Integer status = stageGetAllList.getStatus();
                if (Objects.equals(status, BasicConstant.TWO)) {
                    stageGetAllListPojo = stageGetAllList;
                    stageLogId = stageGetAllListPojo.getStageLogId();
                    stageId = stageGetAllListPojo.getStageId();
                    break;
                }
            }
            List<Map> suspension = stageGetAllListPojo.getSuspension();
            String stageName = stageGetAllListPojo.getStageName();
            // 阶段停留时长
            String timeStay = "";
            // 任务完成情况
            String workCompletion = "";
            // 阶段用时
            String timeUse = "";
            for (Map map : suspension) {
                if (map.containsValue("timeUse")){
                    timeUse = (String) map.get("value");
                    continue;
                }
                if (map.containsValue("timeStay")){
                    timeStay = (String) map.get("value");
                    continue;
                }
                if (map.containsValue("workCompletion")){
                    workCompletion = (String) map.get("value");
                }
            }
            String title = "";
            if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.CUSTOMER_MANAGEMENT)){
                title = paasFormDataEntityExt.getData().get(CustomerManagementEnum.NAME.getAttr()) + "阶段的变更";
            } else if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.SALES_OPPORTUNITY)){
                title = paasFormDataEntityExt.getData().get(SalesOpportunityEnum.NAME.getAttr()) + "阶段的变更";
            }
            String scheduleExplain = "工作完成 " + workCompletion +" 阶段已停留"+ timeStay;
            String time = "";
            if (timeUse.length()>1){
                time = timeUse.substring(0,timeUse.indexOf("至"));
            }
            //阶段详情
            StageDetailDTO stageDetailDTO = new StageDetailDTO();
            BeanUtil.copyProperties(coolAppSendCardDTO,stageDetailDTO);
            stageDetailDTO.setDataId(dataId);
            stageDetailDTO.setFormId(paasFormDataEntityExt.getFormId());
            stageDetailDTO.setBusinessType(xbbRefTypeEnum.getCode());
            stageDetailDTO.setSubBusinessType(subBusinessType);
            stageDetailDTO.setSaasMark(BasicConstant.ONE);
            stageDetailDTO.setCorpid(corpid);
            stageDetailDTO.setUserId(coolAppSendCardDTO.getUserId());
            stageDetailDTO.setDistributorMark(BasicConstant.ZERO);
            stageDetailDTO.setPlatform(PlatFormEnum.DINGTALK.getValue());
            stageDetailDTO.setStageProcessId(stageGetVO.getStageProcessId());
            stageDetailDTO.setStageLogId(stageLogId);
            stageDetailDTO.setStageId(stageId);
            StageDetailVO stageDetailVO = detailStageService.stageDetail(stageDetailDTO);
            List<StageGetOneListPojo> workList = stageDetailVO.getWorkList();
            if (CollectionsUtil.isEmpty(workList)){
                LOG.info("----------workList is null");
            }
            double scheduleNum = 0d;
            double baseRate =  Arith.div(BasicConstant.HUNDRED_PERCENT, workList.size(), BasicConstant.TWO);
            // content数组
            List<Map<String, Object>> stageDetailList = new ArrayList<>();
            Integer numberFiles = 0;
            for (StageGetOneListPojo stageGetOneListPojo : workList) {
                String name = stageGetOneListPojo.getName();
                HashMap<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if (Objects.equals(stageGetOneListPojo.getIsFinished(),BasicConstant.ONE)){
                    map.put("chance","true");
                }else {
                    map.put("chance","false");
                }
                map.put("title","("+stageGetOneListPojo.getProportion()+"%) "+name);
                map.put("explain","描述："+name);
                if (Objects.nonNull(stageGetOneListPojo.getImages()) && stageGetOneListPojo.getImages().size() > 0){
                    numberFiles = numberFiles + stageGetOneListPojo.getImages().size();
                }
                if (Objects.nonNull(stageGetOneListPojo.getAttachments()) && stageGetOneListPojo.getAttachments().size() > 0){
                    numberFiles = numberFiles + stageGetOneListPojo.getAttachments().size();
                }
                stageDetailList.add(map);

                if (Objects.equals(stageGetOneListPojo.getIsFinished(),BasicConstant.ONE)) {
                    // 完成百分比
                    scheduleNum += baseRate;
                }
            }
            if (Arith.sub(BasicConstant.HUNDRED_PERCENT, scheduleNum) <= ConfigConstant.amountAccuracy) {
                scheduleNum = BasicConstant.HUNDRED_PERCENT;
            }

            // 卡片特殊属性json字符串
            CardPropertyPojo cardPropertyPojo = new CardPropertyPojo();
            // 互动卡片参数
            cardPropertyPojo.setAppId(cardDataEntity.getAppId());
            cardPropertyPojo.setMenuId(cardDataEntity.getMenuId());
            cardPropertyPojo.setFormId(cardDataEntity.getFormId());
            cardPropertyPojo.setSaasMark(cardDataEntity.getSaasMark());
            cardPropertyPojo.setBusinessType(cardDataEntity.getBusinessType());
            cardPropertyPojo.setDataId(dataId);
            cardPropertyPojo.setDistributorMark(BasicConstant.ZERO);
            cardPropertyPojo.setSubBusinessType(cardDataEntity.getBusinessType());

            cardDataPojo = formatStageCard(title, scheduleExplain, time, scheduleNum, stageDetailList, cardTemplateExplainPojo, cardPropertyPojo,userIds, detailUrl, numberFiles, stageName);

        return bizManager.sendCard(accessToken, cardDataEntity, cardDataPojo);
    }

    public CardDataPojo formatStageCard(String title, String scheduleExplain, String time, double scheduleNum, List<Map<String, Object>> stageDetailList
            , CardTemplateExplainPojo cardTemplateExplainPojo, CardPropertyPojo cardPropertyPojo, List<String> userIds, String detailUrl,
                                        Integer numberFiles, String stageName){

        Map<String, String> cardData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, Map<String, String>> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 按钮url
        String pcUpdateSageUrl = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl);
        String mobileUpdateSageUrl = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl);
        String pcFeedbackUrl1 = CoolAppConstant.DINGTALK_PC_URL + URLEncodeUtils.encodeURL(detailUrl + "&openStage=1");
        String mobileFeedbackUrl1 = CoolAppConstant.DINGTALK_MOBILE_URL + URLEncodeUtils.encodeURL(detailUrl + "&openStage=1");
        // 按钮绑定url
        JSONObject buttons = cardTemplateExplainPojo.getButtons();
        JSONObject edit = buttons.getJSONObject("edit");
        edit.put("pcUrl",pcUpdateSageUrl);
        edit.put("mobileUrl",mobileUpdateSageUrl);
        JSONObject seeMore = buttons.getJSONObject("feedback");
        seeMore.put("pcUrl",pcFeedbackUrl1);
        seeMore.put("mobileUrl",mobileFeedbackUrl1);
        //标题
        cardData.put("title",title);
        Map<String, Object> hashMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        cardData.put("stageName",stageName);
        cardData.put("time",time);
        cardData.put("scheduleExplain",scheduleExplain);
        cardData.put("scheduleNum",String.valueOf(scheduleNum));
        cardData.put("numberFiles",String.valueOf(numberFiles));
        // 卡片特殊属性json字符串
        hashMap.put("cardPropertyJson",cardPropertyPojo);
        cardData.put(COMPLEX_PARAM, JSON.toJSONString(hashMap));

        // 私有数据
        for (String userId : userIds) {
            Map<String, Object> tempCardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, String> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            //content
            if (CollectionsUtil.isNotEmpty(stageDetailList)){
                tempCardPrivateData.put("content",stageDetailList);
            }
            tempCardPrivateData.put("buttons",  cardTemplateExplainPojo.getButtons());
            map.put(COMPLEX_PARAM,JSON.toJSONString(tempCardPrivateData));
            cardPrivateData.put(userId, map);
        }
        return new CardDataPojo(userIds, cardData, cardPrivateData);
    }

    /**
     * 跟进记录公有必填字段
     * @param requiredAttrList
     * @param userList
     * @param explainMap
     * @param handlerExplainDTO
     * @param commonAttrList
     * @param data
     * @return
     */
    public JSONArray getCommonRequiredList( List<String> requiredAttrList, List<UserEntity> userList,
                                          Map<String, FieldAttrEntity> explainMap, HandlerExplainDTO handlerExplainDTO,
                                          List<String> commonAttrList, JSONObject data) throws XbbException {
        JSONArray resultList = new JSONArray();
        for (String attr : requiredAttrList) {
            boolean commonFlag = true;
            for (UserEntity userEntity : userList) {
                UserVO userVO = new UserVO();
                BeanUtil.copyProperties(userEntity, userVO);
                handlerExplainDTO.setLoginUser(userVO);
                handlerExplainDTO.setUserId(userVO.getUserId());
                commonFlag = commonHelp.attrCanSee(attr, explainMap, handlerExplainDTO);
                if (!commonFlag) {
                    break;
                }
            }
            if (!commonFlag) {
                continue;
            }
            FieldAttrEntity fieldAttrEntity = explainMap.get(attr);
            ItemDataPoJo  itemDataPoJo;
            Object o1 = data.get(attr);
            if (Objects.isNull(o1)){
                continue;
            }
            if (Objects.equals(attr,CustomerCommunicateEnum.COMMUNICATE_TIME.getAttr()) || Objects.equals(attr,CustomerCommunicateEnum.NEXT_COMMUNICATE_TIME.getAttr())
                || Objects.equals(attr,CustomerCommunicateEnum.NOTIFY_TIME.getAttr())){
                Long time = FastJsonHelper.getLongOrDefaultFromFormData(data, attr, DateTimeUtil.getInt());
                String dataTime = DateTimeUtil.getStringEpochSecond(time, DateTimeUtil.SDF);
                itemDataPoJo = new ItemDataPoJo(fieldAttrEntity.getAttrName(), dataTime);
            } else if(Objects.equals(attr,CustomerCommunicateEnum.CUSTOMER_NAME.getAttr()) || Objects.equals(attr,"ownerId")){
                JSONArray jsonArray = data.getJSONArray(attr);
                JSONObject o = (JSONObject) jsonArray.get(0);
                itemDataPoJo = new ItemDataPoJo(fieldAttrEntity.getAttrName(), o.get("name"));
            } else if (Objects.equals(attr,CustomerCommunicateEnum.MEMO.getAttr())){
                String s = data.getString(attr);
                s = formatcontent(s);
                itemDataPoJo = new ItemDataPoJo(fieldAttrEntity.getAttrName(), s);
            } else {
                String value = ItemUtil.parseItemPoJoFromFormData2String(data, attr, "");
                itemDataPoJo = new ItemDataPoJo(fieldAttrEntity.getAttrName(), value);
            }
            resultList.add(itemDataPoJo);
            commonAttrList.add(attr);
        }
        return resultList;
    }



    /**
     * 跟进记录私有content
     * @param requiredAttrList
     * @param userList
     * @param explainMap
     * @param handlerExplainDTO
     * @param commonAttrList
     * @param data
     * @return
     */
    public Map<String, JSONArray> getPrivateRequiredList( List<String> requiredAttrList, List<UserEntity> userList,
                                            Map<String, FieldAttrEntity> explainMap, HandlerExplainDTO handlerExplainDTO,
                                            List<String> commonAttrList, JSONObject data, JSONObject customerCommunicateData) throws XbbException {
        Map<String, JSONArray> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 跟进提醒标识
        Integer isRemind = data.getInteger(CustomerCommunicateEnum.IF_REMIND.getAttr());
        for (String attr : requiredAttrList) {
            if (CollectionsUtil.isNotEmpty(commonAttrList) && commonAttrList.contains(attr)) {
                continue;
            }
            // 去掉关联客户隐藏
            if(Objects.equals(attr,CustomerCommunicateEnum.CUSTOMER_NAME_LINK_TEXT.getAttr())){
                continue;
            }
            for (UserEntity userEntity : userList) {
                UserVO userVO = new UserVO();
                BeanUtil.copyProperties(userEntity, userVO);
                handlerExplainDTO.setLoginUser(userVO);
                handlerExplainDTO.setUserId(userVO.getUserId());
                boolean canSee = commonHelp.attrCanSee(attr, explainMap, handlerExplainDTO);
                Object value = "--";
                if (Objects.equals(attr,CustomerCommunicateEnum.COMMUNICATE_TIME.getAttr()) || (Objects.equals(isRemind,BasicConstant.ONE) && (Objects.equals(attr,CustomerCommunicateEnum.NEXT_COMMUNICATE_TIME.getAttr())
                        || Objects.equals(attr,CustomerCommunicateEnum.NOTIFY_TIME.getAttr())))){
                    Long time = FastJsonHelper.getLongOrDefaultFromFormData(data, attr, DateTimeUtil.getInt());
                    String dataTime = DateTimeUtil.getStringEpochSecond(time, DateTimeUtil.SDF);
                    value = canSee ? dataTime : "--";
                } else if(Objects.equals(attr,CustomerCommunicateEnum.CUSTOMER_NAME.getAttr()) || Objects.equals(attr,"ownerId")){
                    JSONArray jsonArray = data.getJSONArray(attr);
                    JSONObject o = (JSONObject) jsonArray.get(0);
                    value = canSee ? o.get("name") : "--";
                } else if (Objects.equals(attr,CustomerCommunicateEnum.MEMO.getAttr())){
                    String s = data.getString(attr);
                    s = formatcontent(s);
                    value = canSee ? s : "--";
                } else if (canSee) {
                    value = ItemUtil.parseItemPoJoFromFormData2String(data, attr, "");
                }
                // 关联客户隐藏没有value
                if (Objects.isNull(value)){
                    value = canSee ? customerCommunicateData.get(attr) : "--";
                }
                if (Objects.equals(attr,CustomerCommunicateEnum.NOTIFY_TYPE.getAttr()) && Objects.equals(isRemind,BasicConstant.ZERO)){
                    value = "";
                }
                ItemDataPoJo itemDataPoJo = new ItemDataPoJo();
                FieldAttrEntity fieldAttrEntity = explainMap.get(attr);
                itemDataPoJo.setText(fieldAttrEntity.getAttrName());
                itemDataPoJo.setValue(value);

                JSONArray itemDataList = cardPrivateData.getOrDefault(userEntity.getUserId(), new JSONArray());
                itemDataList.add(itemDataPoJo);
                cardPrivateData.put(userEntity.getUserId(), JSONArray.parseArray(itemDataList.toString()));
            }
        }
        return cardPrivateData;
    }

    /**
     * 私有数据摘要
     *
     * @param summaryList
     * @param userList
     * @param explainMap
     * @param handlerExplainDTO
     * @param commonAttrList
     * @return
     */
    private Map<String, JSONArray> getPrivateSummaryList(List<SummaryDataPoJo> summaryList, List<UserEntity> userList,
                                                     Map<String, FieldAttrEntity> explainMap, HandlerExplainDTO handlerExplainDTO,
                                                     List<String> commonAttrList) {

        Map<String, JSONArray> cardPrivateData = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (SummaryDataPoJo dataPoJo : summaryList) {
            if (CollectionsUtil.isNotEmpty(commonAttrList) && commonAttrList.contains(dataPoJo.getAttr())) {
                continue;
            }

            for (UserEntity userEntity : userList) {
                UserVO userVO = new UserVO();
                BeanUtil.copyProperties(userEntity, userVO);
                handlerExplainDTO.setLoginUser(userVO);
                handlerExplainDTO.setUserId(userVO.getUserId());
                boolean canSee = commonHelp.attrCanSee(dataPoJo.getAttr(), explainMap, handlerExplainDTO);
                List<Object> values = dataPoJo.getValue();
                String val = "";
                StringBuilder sb = new StringBuilder();
                if (CollectionsUtil.isNotEmpty(values)) {
                    for (Object value : values) {
                        String s = String.valueOf(value);
                        val = val + s + ",";
                    }
                    sb.append(val.substring(0, val.length() - 1));
                }
                Object value = canSee ? sb.toString() : "--";
                ItemDataPoJo itemDataPoJo = new ItemDataPoJo();
                itemDataPoJo.setText(dataPoJo.getAttrName());
                itemDataPoJo.setValue(value);

                JSONArray itemDataList = cardPrivateData.getOrDefault(userEntity.getUserId(), new JSONArray());
                itemDataList.add(itemDataPoJo);
                cardPrivateData.put(userEntity.getUserId(), JSONArray.parseArray(itemDataList.toString()));
            }
        }
        return cardPrivateData;
    }

    /**
     * 获取审批卡片数据
     *
     * @param corpid
     * @param cardDataEntity
     * @param coolAppSendCardDTO
     * @param cardProcessWorkflowPojo
     * @param receiverUserIdList
     * @param topCardFlag
     * @param updatePojo
     * @return
     */
    private CardDataPojo getProcessOrWorkflowCardData(String corpid, CoolAppCardDataEntity cardDataEntity, CoolAppSendCardDTO coolAppSendCardDTO,
                                             CardProcessWorkflowPojo cardProcessWorkflowPojo, List<String> receiverUserIdList, boolean topCardFlag, CardDataProcessUpdatePojo updatePojo) throws XbbException {
        return coolAppProcessCardService.getProcessOrWorkflowCardData(corpid, cardDataEntity, coolAppSendCardDTO, cardProcessWorkflowPojo, receiverUserIdList, topCardFlag, updatePojo);
    }

    /**
     * 保存卡片发送相关数据
     *
     * @param coolAppSendCardDTO
     * @param cardId
     * @param receiverUserIds
     * @param creatorId
     * @param parentCardBizId
     * @param sourceDataId
     * @param processNode
     * @return
     */
    public CoolAppCardDataEntity saveCardData(CoolAppSendCardDTO coolAppSendCardDTO,String cardId,JSONArray receiverUserIds, String creatorId, String parentCardBizId, Long sourceDataId, JSONObject processNode) throws XbbException {
       return coolAppProcessCardService.saveCardData(coolAppSendCardDTO, cardId, receiverUserIds, creatorId, parentCardBizId, sourceDataId, processNode);

    }


}
